| 1 |
|
|---|
| 2 |
1. Preface. |
|---|
| 3 |
|
|---|
| 4 |
Tcl is easy yet powerful scripting language. climm provides Tcl support |
|---|
| 5 |
both for evaluating Tcl constructions from climm command line and |
|---|
| 6 |
writing Tcl "hooks" to handle different events (incoming messages, |
|---|
| 7 |
status changes, etc). This short HOWTO provides an introduction to |
|---|
| 8 |
writing Tcl scripts for climm. I assume the reader has basic knowledge |
|---|
| 9 |
of Tcl itself - just like I have. ;) |
|---|
| 10 |
|
|---|
| 11 |
Why this HOWTO? When trying to implement a simple hook I discovered |
|---|
| 12 |
that the documentation for this climm functionality is rather sparse |
|---|
| 13 |
and then I had to study climm sources to get my task done. As not |
|---|
| 14 |
everybody can read C source code freely (well, at least I cannot) I |
|---|
| 15 |
decided to try to cover the theme. Hope my efforts will help somebody. |
|---|
| 16 |
|
|---|
| 17 |
Ah, and of course comments and additions are welcome. Reach me at |
|---|
| 18 |
jeff < at > macloue.com. |
|---|
| 19 |
|
|---|
| 20 |
2. Prerequisites - compiling climm with Tcl support. |
|---|
| 21 |
|
|---|
| 22 |
If your system contains a usable Tcl 8.4 installation climm build |
|---|
| 23 |
system will detect it and use automatically. However you can disable |
|---|
| 24 |
Tcl support with --disable-tcl switch - this may give your build a |
|---|
| 25 |
small performance boost. |
|---|
| 26 |
|
|---|
| 27 |
3. Basics. |
|---|
| 28 |
|
|---|
| 29 |
When climm is compiled with Tcl support it creates an internal Tcl |
|---|
| 30 |
interpreter upon startup. The user can use this interpreter to execute |
|---|
| 31 |
tcl code by using one of the following commands at climm promt: |
|---|
| 32 |
|
|---|
| 33 |
tcl <command> |
|---|
| 34 |
|
|---|
| 35 |
Executes inline Tcl <command> in climm Tcl interpreter. |
|---|
| 36 |
|
|---|
| 37 |
Arbitrary Tcl commands can be used, for example: |
|---|
| 38 |
|
|---|
| 39 |
climm> tcl puts [expr 1+2] |
|---|
| 40 |
3 |
|---|
| 41 |
climm> |
|---|
| 42 |
|
|---|
| 43 |
Unlike tclsh climm doesn't automatically echo the result of evaluation |
|---|
| 44 |
so the following command prints nothing: |
|---|
| 45 |
|
|---|
| 46 |
climm> tcl expr 1+2 |
|---|
| 47 |
climm> |
|---|
| 48 |
|
|---|
| 49 |
So remember to "puts" the result of your calculations! |
|---|
| 50 |
|
|---|
| 51 |
tclscript <file> |
|---|
| 52 |
|
|---|
| 53 |
Executes <file> as a Tcl script in scope of climm Tcl interpreter. |
|---|
| 54 |
|
|---|
| 55 |
Supposing that the following script is stored in $HOME/.climm/hello.tcl: |
|---|
| 56 |
|
|---|
| 57 |
puts "Hello, world" |
|---|
| 58 |
|
|---|
| 59 |
the following command will provide: |
|---|
| 60 |
|
|---|
| 61 |
climm> tclscript .climm/hello.tcl |
|---|
| 62 |
Hello, world |
|---|
| 63 |
climm> |
|---|
| 64 |
|
|---|
| 65 |
You can also execute Tcl script upon climm startup by adding option |
|---|
| 66 |
"tclscript" to "[General]" section of your climmrc file. In this case |
|---|
| 67 |
script path can be given relative to climm base directory (usually |
|---|
| 68 |
$HOME/.climm). |
|---|
| 69 |
|
|---|
| 70 |
4. Tcl extensions provided by climm. |
|---|
| 71 |
|
|---|
| 72 |
As most application do, climm provides some extensions to common Tcl |
|---|
| 73 |
syntax. The extension command is "climm" and you can get a short usage |
|---|
| 74 |
description by "climm help" ("tcl climm help" or even "tcl help" from |
|---|
| 75 |
the climm prompt). I will describe "climm" subcommands in slightly more |
|---|
| 76 |
depth below, following Tcl man pages syntax. |
|---|
| 77 |
|
|---|
| 78 |
climm exec <cmd> |
|---|
| 79 |
|
|---|
| 80 |
Executes <cmd> as if it is given at climm command prompt. So, the |
|---|
| 81 |
following code: |
|---|
| 82 |
|
|---|
| 83 |
climm exec "msg Commander Good day, commander!" |
|---|
| 84 |
|
|---|
| 85 |
will send message "Good day, commander!" to Commander contact. |
|---|
| 86 |
|
|---|
| 87 |
climm nick <uin> |
|---|
| 88 |
|
|---|
| 89 |
Finds contact name for <uin>. For example, this code: |
|---|
| 90 |
|
|---|
| 91 |
climm nick 48130434 |
|---|
| 92 |
|
|---|
| 93 |
will return my nickname in your contact list (or empty string if I'm |
|---|
| 94 |
not there). |
|---|
| 95 |
|
|---|
| 96 |
The following commands deal with hooks that can be installed into |
|---|
| 97 |
climm. I will describe them later. |
|---|
| 98 |
|
|---|
| 99 |
climm receive <script> ?<contact>? |
|---|
| 100 |
|
|---|
| 101 |
Installs message hook <script>, invoked on every incoming message or if |
|---|
| 102 |
<contact> is given - on incoming messages from <contact>. |
|---|
| 103 |
|
|---|
| 104 |
climm unreceive ?<contact>? |
|---|
| 105 |
|
|---|
| 106 |
Removes global message hook or message hook for <contact>. |
|---|
| 107 |
|
|---|
| 108 |
[NB: Actually you need to provide exactly the same arguments as to |
|---|
| 109 |
"climm receive" command to successfully remove the hook.] |
|---|
| 110 |
|
|---|
| 111 |
climm event <script> |
|---|
| 112 |
|
|---|
| 113 |
Installs an event hook. |
|---|
| 114 |
|
|---|
| 115 |
climm unevent |
|---|
| 116 |
|
|---|
| 117 |
Removes event hook. |
|---|
| 118 |
|
|---|
| 119 |
[NB: Actually you need to provide exactly the same arguments as to |
|---|
| 120 |
"climm event" command to successfully remove the hook.] |
|---|
| 121 |
|
|---|
| 122 |
climm hooks |
|---|
| 123 |
|
|---|
| 124 |
Returns list (in Tcl meaning, see list(n)) of hooks installed. The list |
|---|
| 125 |
consists of two-element lists with first element being a hook type |
|---|
| 126 |
(either "event hook" for event hook or contact name for receive hooks) |
|---|
| 127 |
and second showing the script which is executed. |
|---|
| 128 |
|
|---|
| 129 |
5. Hooks - basic ideas and examples. |
|---|
| 130 |
|
|---|
| 131 |
When compiled with Tcl support climm can execute different Tcl commands |
|---|
| 132 |
upon certain events. As said above, "climm receive" command can be used |
|---|
| 133 |
to make given <script> to be executed upon incoming message arrival. |
|---|
| 134 |
Actually as far as I can guess from climm source code climm just |
|---|
| 135 |
executes the following construct: |
|---|
| 136 |
|
|---|
| 137 |
<script> <uin> <message> |
|---|
| 138 |
|
|---|
| 139 |
when message <message> is received from UIN <uin>. This requires |
|---|
| 140 |
<script> to be no more than a name of procedure accepting two |
|---|
| 141 |
parameters - or a construction like that: |
|---|
| 142 |
|
|---|
| 143 |
puts "some string"; return; |
|---|
| 144 |
|
|---|
| 145 |
This will make the code executed as follows: |
|---|
| 146 |
|
|---|
| 147 |
puts "some string"; return; 48130434 {Hello!} |
|---|
| 148 |
|
|---|
| 149 |
and hook arguments are ignored - simple but ugly, isn't it? And not as |
|---|
| 150 |
flexible as a procedure too - isn't it useful to know whom we received |
|---|
| 151 |
a message from? |
|---|
| 152 |
|
|---|
| 153 |
But enough chit-chat, let's try to write some hooks already! |
|---|
| 154 |
|
|---|
| 155 |
5.1. Message hooks |
|---|
| 156 |
|
|---|
| 157 |
Message hooks are simple. Unlike event hooks there are always two |
|---|
| 158 |
arguments to the script. Let's write a simple procedure and attach it |
|---|
| 159 |
as a message hook. |
|---|
| 160 |
|
|---|
| 161 |
proc msghook {uin message} {puts "Oh, message from $uin!"} |
|---|
| 162 |
climm receive msghook |
|---|
| 163 |
|
|---|
| 164 |
In climm prompt this will look as follows: |
|---|
| 165 |
|
|---|
| 166 |
climm> tcl proc msghook {uin message} {puts "Oh, message from $uin!"} |
|---|
| 167 |
climm> tcl climm receive msghook |
|---|
| 168 |
|
|---|
| 169 |
Let's try to test it: |
|---|
| 170 |
|
|---|
| 171 |
climm> msg 48130434 test |
|---|
| 172 |
14:39:13 48130434 {<< test |
|---|
| 173 |
Oh, message from 48130434! |
|---|
| 174 |
14:39:14 48130434 >>} test |
|---|
| 175 |
|
|---|
| 176 |
It works, doesn't it? Then let's try to remove the hook: |
|---|
| 177 |
|
|---|
| 178 |
climm> tcl climm unreceive msghook |
|---|
| 179 |
|
|---|
| 180 |
The hook is now removed. |
|---|
| 181 |
|
|---|
| 182 |
This hook was global, let's make it filter UINs. |
|---|
| 183 |
|
|---|
| 184 |
climm> tcl climm receive msghook Larry_Laffer |
|---|
| 185 |
climm> msg 48130434 test |
|---|
| 186 |
14:42:35 48130434 {<< test |
|---|
| 187 |
14:42:35 48130434 >>} test |
|---|
| 188 |
|
|---|
| 189 |
The hook is not executed. To remove it we need to give the following |
|---|
| 190 |
command: |
|---|
| 191 |
|
|---|
| 192 |
climm> tcl climm unreceive msghook Larry_Laffer |
|---|
| 193 |
|
|---|
| 194 |
5.2. Event hooks |
|---|
| 195 |
|
|---|
| 196 |
Event hooks are complex. At the moment of writing climm doesn't |
|---|
| 197 |
distinguish different event types - there is only one global event hook |
|---|
| 198 |
and it is called with variable number of parameters. The first is |
|---|
| 199 |
always an event type - so it's up to hook procedure to decide whether |
|---|
| 200 |
to continue processing or return. Second is always UIN of the contact |
|---|
| 201 |
who triggered the event. Other parameters can vary so precautions need |
|---|
| 202 |
to be made not to receive many error messages. |
|---|
| 203 |
|
|---|
| 204 |
5.2.1. Event: status change. |
|---|
| 205 |
|
|---|
| 206 |
Let's try to implement simple "status change" event handler. Status |
|---|
| 207 |
change event happens every time a contact changes its status |
|---|
| 208 |
(naturally) and executes the following Tcl code: |
|---|
| 209 |
|
|---|
| 210 |
<event handler script> status <uin> <status> |
|---|
| 211 |
|
|---|
| 212 |
So, let's write something like this: |
|---|
| 213 |
|
|---|
| 214 |
proc evhandler {type uin args} { |
|---|
| 215 |
if { $type != "status" } then return |
|---|
| 216 |
set status [lindex $args 0] |
|---|
| 217 |
set nick [climm nick $uin] |
|---|
| 218 |
puts "$nick changes status to $status" |
|---|
| 219 |
} |
|---|
| 220 |
|
|---|
| 221 |
This procedure analyzes event type and if it is a status change event |
|---|
| 222 |
extracts status value and prints a message. Let's attach it as an event |
|---|
| 223 |
handler: |
|---|
| 224 |
|
|---|
| 225 |
climm event evhandler |
|---|
| 226 |
|
|---|
| 227 |
If the procedure is stored in file $HOME/.climm/evhandler.tcl the |
|---|
| 228 |
following commands will do the trick: |
|---|
| 229 |
|
|---|
| 230 |
climm> tclscript .climm/evhandler.tcl |
|---|
| 231 |
climm> tcl climm event evhandler |
|---|
| 232 |
|
|---|
| 233 |
Then, when a contact changes his/her status, we will get the following: |
|---|
| 234 |
|
|---|
| 235 |
15:17:46 Contact1 changed status to occupied. |
|---|
| 236 |
Contact1 changes status to occupied |
|---|
| 237 |
|
|---|
| 238 |
Or even: |
|---|
| 239 |
|
|---|
| 240 |
15:19:39 Contact2 logged off. |
|---|
| 241 |
Contact2 changes status to logged_off |
|---|
| 242 |
|
|---|
| 243 |
Going offline is also a status change. |
|---|
| 244 |
|
|---|
| 245 |
6. Hooks reference. |
|---|
| 246 |
|
|---|
| 247 |
6.1. Message hook. |
|---|
| 248 |
|
|---|
| 249 |
Install syntax: |
|---|
| 250 |
|
|---|
| 251 |
climm receive <script> ?<contact>? |
|---|
| 252 |
|
|---|
| 253 |
Remove syntax: |
|---|
| 254 |
|
|---|
| 255 |
climm unreceive <script> ?<contact>? |
|---|
| 256 |
|
|---|
| 257 |
Tcl code executed upon message arrival (from <contact> if specified): |
|---|
| 258 |
|
|---|
| 259 |
<script> <uin> <message> |
|---|
| 260 |
|
|---|
| 261 |
6.2. Event hooks. |
|---|
| 262 |
|
|---|
| 263 |
Install syntax: |
|---|
| 264 |
|
|---|
| 265 |
climm event <script> |
|---|
| 266 |
|
|---|
| 267 |
Remove syntax: |
|---|
| 268 |
|
|---|
| 269 |
climm unevent <script> |
|---|
| 270 |
|
|---|
| 271 |
Tcl code executed upon event: |
|---|
| 272 |
|
|---|
| 273 |
<script> <type> <uin> ?<arg1>? ... |
|---|
| 274 |
|
|---|
| 275 |
List of optional arguments depends on event <type>. |
|---|
| 276 |
|
|---|
| 277 |
6.2.1. Event: status change. |
|---|
| 278 |
|
|---|
| 279 |
When a contact <uin> changes his status to <status> the following Tcl |
|---|
| 280 |
code is executed: |
|---|
| 281 |
|
|---|
| 282 |
<script> status <uin> <status> |
|---|
| 283 |
|
|---|
| 284 |
6.2.2. Event: message received. |
|---|
| 285 |
|
|---|
| 286 |
This event is triggered when incoming message arrives. Although it's |
|---|
| 287 |
better to use message hooks to handle events of this type you can |
|---|
| 288 |
handle messages through the event hook as well - it may useful in some |
|---|
| 289 |
cases because message and event hooks are invoked independently. |
|---|
| 290 |
|
|---|
| 291 |
When a message <message> is received from user <uin> the following Tcl |
|---|
| 292 |
code executed is as follows: |
|---|
| 293 |
|
|---|
| 294 |
<script> message <uin> <message> |
|---|
| 295 |
|
|---|
| 296 |
6.2.3. Event: incoming file request. |
|---|
| 297 |
|
|---|
| 298 |
This event is triggered when file transfer request arrives. The |
|---|
| 299 |
following Tcl code is executed: |
|---|
| 300 |
|
|---|
| 301 |
<script> file_request <uin> <file name> <bytes> <ref> |
|---|
| 302 |
|
|---|
| 303 |
FIXME: I don't know much about ICQ file transfers, so can somebody tell |
|---|
| 304 |
me what the <ref> is? |
|---|
| 305 |
|
|---|
| 306 |
6.2.4. Event: added to contact list. |
|---|
| 307 |
|
|---|
| 308 |
This event is triggered when you are added to somebody's contact list. |
|---|
| 309 |
When user <uin> adds you to his contact list the following Tcl code is |
|---|
| 310 |
executed: |
|---|
| 311 |
|
|---|
| 312 |
<script> contactlistadded <uin> |
|---|
| 313 |
|
|---|
| 314 |
6.2.5. Event: authorization. |
|---|
| 315 |
|
|---|
| 316 |
Events of this group are triggered when authorization messages arrive. |
|---|
| 317 |
When auth message arrives from user <uin> the following Tcl code is |
|---|
| 318 |
executed: |
|---|
| 319 |
|
|---|
| 320 |
<script> authorization <uin> <authtype> |
|---|
| 321 |
|
|---|
| 322 |
<authtype> can be: |
|---|
| 323 |
|
|---|
| 324 |
- request - when incoming auth request is received from user <uin>; |
|---|
| 325 |
- refused - if your auth request is refused by user <uin>; |
|---|
| 326 |
- granted - if your auth request is granted by user <uin>. |
|---|
| 327 |
|
|---|
| 328 |
6.2.6. Event: Web message arrived. |
|---|
| 329 |
|
|---|
| 330 |
This event is triggered when you receive a message from ICQ web site |
|---|
| 331 |
("web message"). The following Tcl code is executed: |
|---|
| 332 |
|
|---|
| 333 |
<script> web <uin> <t0> <t3> <t4> <t5> |
|---|
| 334 |
|
|---|
| 335 |
FIXME: add t0-t5 parameters description; not sure what <uin> is in this |
|---|
| 336 |
case. |
|---|
| 337 |
|
|---|
| 338 |
6.2.7. Event: Mail message arrived. |
|---|
| 339 |
|
|---|
| 340 |
This event is triggered when you receive a ICQ Mail message. The |
|---|
| 341 |
following Tcl code is executed: |
|---|
| 342 |
|
|---|
| 343 |
<script> mail <uin> <t0> <t3> <t4> <t5> |
|---|
| 344 |
|
|---|
| 345 |
FIXME: add t0-t5 parameters description; not sure what <uin> is in this case |
|---|
| 346 |
|
|---|
| 347 |
6.2.8. Event: SSL. |
|---|
| 348 |
|
|---|
| 349 |
Events of this group are triggered at various stage of SSL connection setup. |
|---|
| 350 |
|
|---|
| 351 |
When it is detected that the user <uin>'s client doesn't support SSL |
|---|
| 352 |
channel the following Tcl code is executed: |
|---|
| 353 |
|
|---|
| 354 |
<script> ssl <uin> no_candidate |
|---|
| 355 |
|
|---|
| 356 |
When it is detected that the user <uin>'s client supports SSL channel |
|---|
| 357 |
the following Tcl code is executed: |
|---|
| 358 |
|
|---|
| 359 |
<script> ssl <uin> candidate |
|---|
| 360 |
|
|---|
| 361 |
When SSL connection is tried to user <uin>, the following Tcl code is |
|---|
| 362 |
executed if remote hasn't SSL connetion enabled: |
|---|
| 363 |
|
|---|
| 364 |
<script> ssl <uin> failed precondition |
|---|
| 365 |
|
|---|
| 366 |
When SSL connection is tried to user <uin>, the following Tcl code is |
|---|
| 367 |
executed if SSL connection initialization fails: |
|---|
| 368 |
|
|---|
| 369 |
<script> ssl <uin> failed init |
|---|
| 370 |
|
|---|
| 371 |
When SSL connection is tried to user <uin>, the following Tcl code is |
|---|
| 372 |
executed if SSL key exchange fails: |
|---|
| 373 |
|
|---|
| 374 |
<script> ssl <uin> failed key |
|---|
| 375 |
|
|---|
| 376 |
When SSL connection is tried to user <uin>, the following Tcl code is |
|---|
| 377 |
executed if SSL handshake fails: |
|---|
| 378 |
|
|---|
| 379 |
<script> ssl <uin> failed handshake |
|---|
| 380 |
|
|---|
| 381 |
And, finally, when SSL connection to user <uin> is successfully |
|---|
| 382 |
established the following Tcl code is executed: |
|---|
| 383 |
|
|---|
| 384 |
<script> ssl <uin> ok |
|---|
| 385 |
|
|---|
| 386 |
If the SSL connection to <uin> fails at some stage finally the |
|---|
| 387 |
following Tcl code is executed: |
|---|
| 388 |
|
|---|
| 389 |
<script> ssl <uin> incapable |
|---|