| 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 |
|---|