summary refs log tree commit diff stats
path: root/python.md
blob: aa8ca56e446cff29aae0b50251d5c1727988efc4 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
% HexChat Python Interface

Features
--------

Here are some of the features of the python plugin interface:

-   Comprehensive, consistent and straightforward API
-   Load, unload, reload, and autoload support
-   Per plugin independent interpreter state
-   Python interactive console
-   Python interactive command execution
-   Full thread support
-   Stdout and stderr redirected to xchat console
-   Dynamic list management
-   Nice context treatment
-   Plugin preferences

Commands
--------

The following commands will be intercepted by the Python Plugin
interface module, when it is loaded.

----------------------------------------------------------------------------------------------------------------------------------------------
*Command*                               *Description*
-----------------------------------     ------------------------------------------------------------------------------------------------------
/py load <filename>                   Load module with given filename.

/py unload <filename|module name>     Unload module with given filename, or module name.

/py reload <filename|module name>     Reload module with given filename, or module name.

/py list                                List Python modules loaded.

/py exec <command>                    Execute given Python command interactively. For example:
                                            `/py exec import xchat`
                                            `/py exec print xchat.get_info('channel')`

/py console                             Open the Python interactive console in a query (>>python<<).
                                        Every message sent will be intercepted by the Python plugin interface, and interpreted interactively.
                                        Notice that the console and /py exec commands live in the same interpreter state.

/py about                               Show some information about the Python plugin interface.
----------------------------------------------------------------------------------------------------------------------------------------------


Autoloading modules
-------------------

If you want some module to be autoloaded together with the Python plugin
interface (which usually loads at startup time), just make sure it has a
`.py` extension and put it in your HexChat directory (~/.config/hexchat/addons, %APPDATA%\\HexChat\\addons).

Context theory
--------------

Before starting to explain what the API offers, I'll do a short
introduction about the xchat context concept. Not because it's something
hard to understand, but because you'll understand better the API
explanations if you know what I'm talking about.

You can think about a context as an xchat channel, server, or query tab.
Each of these tabs, has its own context, and is related to a given
server and channel (queries are a special kind of channel).

The *current* context is the one where xchat passes control to the
module. For example, when xchat receives a command in a specific
channel, and you have asked xchat to tell you about this event, the
current context will be set to this channel before your module is
called.

Hello world
-----------

Here is the traditional *hello world* example.

~~~~~~~~~~ {.python}
    __module_name__ = "helloworld" 
    __module_version__ = "1.0" 
    __module_description__ = "Python module example" 
     
    print "Hello world!" 
~~~~~~~~~~

This module will print "Hello world!" in the xchat console, and sleep
forever until it's unloaded. It's a simple module, but already
introduces some concepts. Notice how the module information is set. This
information is obligatory, and will be shown when listing the loaded
xchat modules.

xchat module
------------

The xchat module is your passport to every xchat functionality offered
by the Python plugin interface. Here's a simple example:

~~~~~~~~~~ {.python}
    import xchat 
    xchat.prnt("Hi everyone!")
~~~~~~~~~~

The following functions are available in the xchat module.

### Generic functions

#### xchat.prnt(string)

This function will print string in the current context. It's mainly
useful as a parameter to pass to some other function, since the usual
print statement will have the same results. You have a usage example
above.

This function is badly
named because `"print"` is a reserved keyword of the Python language.

#### xchat.emit_print(event_name, *args)

This function will generate a *print event* with the given arguments. To
check which events are available, and the number and meaning of
arguments, have a look at the `Settings > Lists > Text Events` window.
Here is one example:

~~~~~~~~~~ {.python}
    xchat.emit_print("Channel Message", "John", "Hi there", "@")
~~~~~~~~~~`

#### xchat.command(string)

Execute the given command in the current context. This has the same
results as executing a command in the xchat window, but notice that the
`/` prefix is not used. Here is an example:

~~~~~~~~~~ {.python}
    xchat.command("server irc.openprojects.net") 
~~~~~~~~~~

#### xchat.nickcmp(s1, s2)

This function will do an RFC1459 compliant string comparing between `s1`
and `s2`, and is useful to compare channels and nicknames. It returns an
integer less than, equal to, or greater than zero if `s1` is found,
respectively, to be less than, to match, or be greater than `s2`. For
example:

~~~~~~~~~~ {.python}
    if xchat.nickcmp(nick, "mynick") == 0: 
        print "They are the same!" 
~~~~~~~~~~

### Information retreiving functions

#### xchat.get_info(type)

Retrieve the information specified by the `type` string in the current
context. At the moment of this writing, the following information types
are available to be queried:

-----------------------------------------------------------------------------------------------
*Type*      *Description*
--------    -----------------------------------------------------------------------------------
away        Away reason or None if you are not away.

channels    Channel of the current context.

hostname    Real hostname of the server you connected to.

network     Current network name or None.

nick        Your current nick name.

server      Current server name (what the server claims to be) or None if you are not connected.

topic       Current channel topic.

version     hexchat version number.

xchatdir    hexchat config directory e.g.: "~/.config/hexchat".
------------------------------------------------------------------------------------------------

Example:

~~~~~~~~~~ {.python}
    if xchat.get_info("server") is None: 
        xchat.prnt("Not connected!") 
~~~~~~~~~~

#### xchat.get_prefs(name)

Retrieve the xchat setting information specified by the `name` string,
as available by the `/set` command. For example:

~~~~~~~~~~ {.python}
    print "Current preferred nick:", xchat.get_prefs("irc_nick1")
~~~~~~~~~~

#### xchat.get_list(type)

With this function you may retrieve a list containing the selected
information from the current context, like a DCC list, a channel list, a
user list, etc. Each list item will have its attributes set dynamically
depending on the information provided by the list type.

The example below is a rewrite of the example provided with xchat's
plugin API documentation. It prints a list of every DCC transfer
happening at the moment. Notice how similar the interface is to the C
API provided by xchat.

~~~~~~~~~~ {.python}
    list = xchat.get_list("dcc") 
    if list: 
        print "--- DCC LIST ------------------" 
        print "File  To/From   KB/s   Position" 
        for i in list: 
            print "%6s %10s %.2f  %d" % (i.file, i.nick, i.cps/1024, i.pos) 
~~~~~~~~~~

Below you will find what each list type has to offer.

This information was
taken from xchat's plugin documentation. You may find any types not
listed here, if they exist at all, in an updated xchat documentation.
Any list types accepted by xchat should be dynamically accepted by the
Python plugin interface.

##### channels

The channels list type gives you access to the channels, queries and
their servers. The folloing attributes are available in each list item:

------------------------------------------------------------------
*Type*      *Description*
-------     ------------------------------------------------------
channel     Channel or query name.

context     A context object, giving access to that channel/server.

network     Network name to which this channel belongs.

server      Server name to which this channel belongs.

type        Type of context (1=Server, 2=Channel, 3=Dialog).
------------------------------------------------------------------

##### dcc

The dcc list type gives you access to a list of DCC file transfers. The
following attributes are available in each list item:

--------------------------------------------------------------------------------------
*Type*      *Description*
---------   --------------------------------------------------------------------------
address32   Address of the remote user (ipv4 address, as an int).

cps         Bytes per second (speed).

destfile    Destination full pathname.

file        Filename.

nick        Nickname of person who the file is from/to.

port        TCP port number.

pos         Bytes sent/received.

resume      Point at which this file was resumed (or zero if it was not resumed).

size        File size in bytes.

status      DCC status (queued=0, active=1, failed=2, done=3, connecting=4, aborted=5).

type        DCC type (send=0, receive=1, chatrecv=2, chatsend=3).
--------------------------------------------------------------------------------------

##### users

The users list type gives you access to a list of users in the current
channel. The following attributes are available in each list item:

----------------------------------------------------------------
*Type*  *Description*
------  --------------------------------------------------------
nick    Nick name.

host    Host name in the form user@host (or None, if not known).

prefix  Prefix character, .e.g: @ or +. Points to a single char.
----------------------------------------------------------------

##### ignore

The ignore list type gives you access to the current ignored list. The
following attributes are available in each list item:

-----------------------------------------------------------------------------------------------------------
*Type*  *Description*
-----   ---------------------------------------------------------------------------------------------------
mask    Ignore mask (for example, "*!*@*.aol.com").
flags   Bit field of flags (0=private, 1=notice, 2=channel, 3=ctcp, 4=invite, 5=unignore, 6=nosave, 7=dcc).
-----------------------------------------------------------------------------------------------------------

### Hook functions

These functions allow one to hook into xchat events.

#### Priorities

When a priority keyword parameter is accepted, it means that this
callback may be hooked with five different priorities: PRI_HIGHEST,
PRI_HIGH, PRI_NORM, PRI_LOW, and PRI_LOWEST. The usage of these
constants, which are available in the xchat module, will define the
order in which your plugin will be called. Most of the time, you won't
want to change its default value (PRI_NORM).

#### Parameters word and word_eol

These parameters, when available in a callback, are lists of strings
which contain the parameters the user entered for the particular
command. For example, if you executed:

> /command NICK Hi there! 

-   **word[0]** is `command`
-   **word[1]** is `NICK`
-   **word[2]** is `Hi`
-   **word[3]** is `there!`
-   **word_eol[0]** is `command NICK Hi there!`
-   **word_eol[1]** is `NICK Hi there!`
-   **word_eol[2]** is `Hi there!`
-   **word_eol[3]** is `there!`

#### Parameter userdata

The parameter userdata, if given, allows you to pass a custom object to
your callback.

#### Callback return constants (EAT_*)

When a callback is supposed to return one of the EAT_* macros, it is
able control how xchat will proceed after the callback returns. These
are the available constants, and their meanings:

----------------------------------------------------------
*Constant*  *Description*
----------- ----------------------------------------------
EAT_PLUGIN Don't let any other plugin receive this event.

EAT_XCHAT  Don't let xchat treat this event as usual.

EAT_ALL    Eat the event completely.

EAT_NONE   Let everything happen as usual.
-----------------------------------------------------------

Returning `None` is the same as returning `EAT_NONE`.

#### xchat.hook_command(name, callback, userdata=None, priority=PRI_NORM, help=None)

This function allows you to hook into the name xchat command. It means
that everytime you type `/name ...`, `callback` will be called.
Parameters `userdata` and `priority` have their meanings explained
above, and the parameter help, if given, allows you to pass a help text
which will be shown when `/help name` is executed. This function returns
a hook handler which may be used in the `xchat.unhook()` function. For
example:

~~~~~~~~~~ {.python}
    def onotice_cb(word, word_eol, userdata): 
        if len(word) < 2: 
            print "Second arg must be the message!" 
        else: 
            xchat.command("NOTICE @%s %s" % (xchat.get_info("channel"), word_eol[1])) 
        return xchat.EAT_ALL 
     
    xchat.hook_command("ONOTICE", onotice_cb, help="/ONOTICE <message> Sends a notice to all ops")
~~~~~~~~~~

You may return one of `EAT_*` constants in the callback, to control
xchat's behavior, as explained above.

#### xchat.hook_print(name, callback, userdata=None, priority=PRI_NORM)

This function allows you to register a callback to trap any print
events. The event names are available in the *Edit Event Texts* window.
Parameters `userdata` and `priority` have their meanings explained
above. This function returns a hook handler which may be used in the
`xchat.unhook()` function. For example:

~~~~~~~~~~ {.python}
    def youpart_cb(word, word_eol, userdata): 
        print "You have left channel", word[2] 
        return xchat.EAT_XCHAT # Don't let xchat do its normal printing 
     
    xchat.hook_print("You Part", youpart_cb) 
~~~~~~~~~~

You may return one of `EAT_*` constants in the callback, to control
xchat's behavior, as explained above.

#### xchat.hook_server(name, callback, userdata=None, priority=PRI_NORM)

This function allows you to register a callback to be called when a
certain server event occurs. You can use this to trap `PRIVMSG`,
`NOTICE`, `PART`, a server numeric, etc. Parameters `userdata` and
`priority` have their meanings explained above. This function returns a
hook handler which may be used in the `xchat.unhook()` function. For
example:

~~~~~~~~~~ {.python}
    def kick_cb(word, word_eol, userdata): 
        print "%s was kicked from %s (%s)" % (word[3], word[2], word_eol[4]) 
        # Don't eat this event, let other plugins and xchat see it too 
        return xchat.EAT_NONE 
     
    xchat.hook_server("KICK", kick_cb) 
~~~~~~~~~~

You may return one of `EAT_*` constants in the callback, to control
xchat's behavior, as explained above.

#### xchat.hook_timer(timeout, callback, userdata=None)

This function allows you to register a callback to be called every
timeout milliseconds. Parameters userdata and priority have their
meanings explained above. This function returns a hook handler which may
be used in the `xchat.unhook()` function. For example:

~~~~~~~~~~ {.python}
    myhook = None 
     
    def stop_cb(word, word_eol, userdata): 
        global myhook 
        if myhook is not None: 
            xchat.unhook(myhook) 
            myhook = None 
            print "Timeout removed!" 
     
    def timeout_cb(userdata): 
        print "Annoying message every 5 seconds! Type /STOP to stop it." 
        return 1 # Keep the timeout going 
     
    myhook = xchat.hook_timer(5000, timeout_cb) 
    xchat.hook_command("STOP", stop_cb) 
~~~~~~~~~~

If you return a true value from the callback, the timer will be keeped,
otherwise it is removed.

#### xchat.hook_unload(timeout, callback, userdata=None)

This function allows you to register a callback to be called when the
plugin is going to be unloaded. Parameters `userdata` and `priority`
have their meanings explained above. This function returns a hook
handler which may be used in the `xchat.unhook()` function. For example:

~~~~~~~~~~ {.python}
    def unload_cb(userdata): 
        print "We're being unloaded!" 
     
    xchat.hook_unload(unload_cb) 
~~~~~~~~~~

#### xchat.unhook(handler)

Unhooks any hook registered with the hook functions above.

### Plugin preferences

You can use pluginpref to easily store and retrieve settings. This was added in the Python plugin version 0.9

#### xchat.set_pluginpref(name, value)

If neccessary creates a .conf file in the HexChat config dir named addon_python.conf and stores the value in it. Returns 1 on success 0 on failure.

> Note: Until the plugin uses different a conf file per script it's recommened to use 'PluginName-SettingName' to avoid conflicts.

#### xchat.get_pluginpref(name)

This will return the value of the variable of that name. If there is none by this name it will return `None`. Numbers are always returned as Integers.

#### xchat.del_pluginpref(name)

Deletes specified variable. Returns 1 on success (or never existing), 0 on failure.

#### xchat.list_pluginpref()

Returns a list of all currently set preferences.

### Context handling

Below you will find information about how to work with contexts.

#### Context objects

As explained in the Context theory session above, contexts give access
to a specific channel/query/server tab of xchat. Every function
available in the xchat module will be evaluated in the current context,
which will be specified by xchat itself before passing control to the
module. Sometimes you may want to work in a specific context, and that's
where context objects come into play.

You may create a context object using the `xchat.get_context()` or
`xchat.find_context()`, functions as explained below, or trough the
`xchat.get_list()` function, as explained in its respective session.

Each context object offers the following methods:

-------------------------------------------------------------------------------------------------------------------------
*Methods*                                   *Description*
----------------------------------------    -----------------------------------------------------------------------------
context.set()                               Changes the current context to be the one represented by this context object.

context.prnt(string)                        Does the same as the xchat.prnt() function, but in the given context.

context.emit_print(event_name, *args)    Does the same as the emit_print() function, but in the given context.

context.command(string)                     Does the same as the xchat.command() function, but in the given context.

context.get_info(type)                     Does the same as the xchat.get_info() function, but in the given context.

context.get_list(type)                     Does the same as the xchat.get_list() function, but in the given context.
-------------------------------------------------------------------------------------------------------------------------

#### xchat.get_context()

Returns a context object corresponding the the current context.

#### xchat.find_context(server=None, channel=None)

Finds a context based on a channel and servername. If `server` is
`None`, it finds any channel (or query) by the given name. If `channel`
is `None`, it finds the front-most tab/window of the given server. For
example:

~~~~~~~~~~ {.python}
    cnc = xchat.find_context(channel='#conectiva') 
    cnc.command('whois niemeyer') 
~~~~~~~~~~

* * * * *

Original Author: Gustavo Niemeyer [gustavo@niemeyer.net](mailto:gustavo@niemeyer.net)