Bug Summary

File:core/expandos.c
Location:line 139, column 2
Description:Dereference of null pointer.

Annotated Source Code

1/*
2 expandos.c : irssi
3
4 Copyright (C) 2000 Timo Sirainen
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License along
17 with this program; if not, write to the Free Software Foundation, Inc.,
18 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19*/
20
21#include "core.h"
22#include "module.h"
23#include "modules.h"
24#include "signals.h"
25#include "expandos.h"
26#include "settings.h"
27#include "commands.h"
28#include "misc.h"
29#include "irssi-version.h"
30
31#include "servers.h"
32#include "channels.h"
33#include "queries.h"
34#include "window-item-def.h"
35
36#ifdef HAVE_SYS_UTSNAME_H1
37# include <sys/utsname.h>
38#endif
39
40#define MAX_EXPANDO_SIGNALS10 10
41
42typedef struct {
43 EXPANDO_FUNC func;
44
45 int signals;
46 int signal_ids[MAX_EXPANDO_SIGNALS10];
47 int signal_args[MAX_EXPANDO_SIGNALS10];
48} EXPANDO_REC;
49
50const char *current_expando = NULL((void *)0);
51
52static int timer_tag;
53
54static EXPANDO_REC *char_expandos[255];
55static GHashTable *expandos;
56static char *last_sent_msg, *last_sent_msg_body;
57static char *last_privmsg_from, *last_public_from;
58static char *sysname, *sysrelease, *sysarch;
59
60static const char *timestamp_format;
61static int timestamp_seconds;
62static time_t last_timestamp;
63
64#define CHAR_EXPANDO(chr)(char_expandos[(int) (unsigned char) chr]) \
65 (char_expandos[(int) (unsigned char) chr])
66
67/* Create expando - overrides any existing ones. */
68void expando_create(const char *key, EXPANDO_FUNC func, ...)
69{
70 EXPANDO_REC *rec;
71 const char *signal;
72 va_list va;
73
74 g_return_if_fail(key != NULL || *key == '\0')do{ if (key != ((void *)0) || *key == '\0') { } else { g_return_if_fail_warning
(((gchar*) 0), __PRETTY_FUNCTION__, "key != NULL || *key == '\\0'"
); return; }; }while (0)
;
75 g_return_if_fail(func != NULL)do{ if (func != ((void *)0)) { } else { g_return_if_fail_warning
(((gchar*) 0), __PRETTY_FUNCTION__, "func != NULL"); return;
}; }while (0)
;
76
77 if (key[1] != '\0')
78 rec = g_hash_table_lookup(expandos, key);
79 else {
80 /* single character expando */
81 rec = CHAR_EXPANDO(*key)(char_expandos[(int) (unsigned char) *key]);
82 }
83
84 if (rec != NULL((void *)0))
85 rec->signals = 0;
86 else {
87 rec = g_new0(EXPANDO_REC, 1)((EXPANDO_REC *) g_malloc0 (((gsize) sizeof (EXPANDO_REC)) * (
(gsize) (1))))
;
88 if (key[1] != '\0')
89 g_hash_table_insert(expandos, g_strdup(key), rec);
90 else
91 char_expandos[(int) (unsigned char) *key] = rec;
92 }
93
94 rec->func = func;
95
96 va_start(va, func)__builtin_va_start((va), (func));
97 while ((signal = (const char *) va_arg(va, const char *)__builtin_va_arg((va), const char *)) != NULL((void *)0))
98 expando_add_signal(key, signal, (int) va_arg(va, int)__builtin_va_arg((va), int));
99 va_end(va)__builtin_va_end(va);
100}
101
102static EXPANDO_REC *expando_find(const char *key)
103{
104 if (key[1] != '\0')
105 return g_hash_table_lookup(expandos, key);
106 else
107 return CHAR_EXPANDO(*key)(char_expandos[(int) (unsigned char) *key]);
108}
109
110/* Add new signal to expando */
111void expando_add_signal(const char *key, const char *signal, ExpandoArg arg)
112{
113 EXPANDO_REC *rec;
114
115 g_return_if_fail(key != NULL)do{ if (key != ((void *)0)) { } else { g_return_if_fail_warning
(((gchar*) 0), __PRETTY_FUNCTION__, "key != NULL"); return; }
; }while (0)
;
116 g_return_if_fail(signal != NULL)do{ if (signal != ((void *)0)) { } else { g_return_if_fail_warning
(((gchar*) 0), __PRETTY_FUNCTION__, "signal != NULL"); return
; }; }while (0)
;
117
118 rec = expando_find(key);
119 g_return_if_fail(rec != NULL)do{ if (rec != ((void *)0)) { } else { g_return_if_fail_warning
(((gchar*) 0), __PRETTY_FUNCTION__, "rec != NULL"); return; }
; }while (0)
;
120
121 if (arg == EXPANDO_NEVER) {
122 /* expando changes never */
123 rec->signals = -1;
124 } else if (rec->signals < MAX_EXPANDO_SIGNALS10) {
125 g_return_if_fail(rec->signals != -1)do{ if (rec->signals != -1) { } else { g_return_if_fail_warning
(((gchar*) 0), __PRETTY_FUNCTION__, "rec->signals != -1")
; return; }; }while (0)
;
126
127 rec->signal_ids[rec->signals] = signal_get_uniq_id(signal)module_get_uniq_id_str("signals", signal);
128 rec->signal_args[rec->signals] = arg;
129 rec->signals++;
130 }
131}
132
133/* Destroy expando */
134void expando_destroy(const char *key, EXPANDO_FUNC func)
135{
136 gpointer origkey, value;
137 EXPANDO_REC *rec;
138
139 g_return_if_fail(key != NULL || *key == '\0')do{ if (key != ((void *)0) || *key == '\0') { } else { g_return_if_fail_warning
(((gchar*) 0), __PRETTY_FUNCTION__, "key != NULL || *key == '\\0'"
); return; }; }while (0)
;
Dereference of null pointer
140 g_return_if_fail(func != NULL)do{ if (func != ((void *)0)) { } else { g_return_if_fail_warning
(((gchar*) 0), __PRETTY_FUNCTION__, "func != NULL"); return;
}; }while (0)
;
141
142 if (key[1] == '\0') {
143 /* single character expando */
144 rec = CHAR_EXPANDO(*key)(char_expandos[(int) (unsigned char) *key]);
145 if (rec != NULL((void *)0) && rec->func == func) {
146 char_expandos[(int) (unsigned char) *key] = NULL((void *)0);
147 g_free(rec);
148 }
149 } else if (g_hash_table_lookup_extended(expandos, key,
150 &origkey, &value)) {
151 rec = value;
152 if (rec->func == func) {
153 g_hash_table_remove(expandos, key);
154 g_free(origkey);
155 g_free(rec);
156 }
157 }
158}
159
160void expando_bind(const char *key, int funccount, SIGNAL_FUNC *funcs)
161{
162 SIGNAL_FUNC func;
163 EXPANDO_REC *rec;
164 int n, arg;
165
166 g_return_if_fail(key != NULL)do{ if (key != ((void *)0)) { } else { g_return_if_fail_warning
(((gchar*) 0), __PRETTY_FUNCTION__, "key != NULL"); return; }
; }while (0)
;
167 g_return_if_fail(funccount >= 1)do{ if (funccount >= 1) { } else { g_return_if_fail_warning
(((gchar*) 0), __PRETTY_FUNCTION__, "funccount >= 1"); return
; }; }while (0)
;
168 g_return_if_fail(funcs != NULL)do{ if (funcs != ((void *)0)) { } else { g_return_if_fail_warning
(((gchar*) 0), __PRETTY_FUNCTION__, "funcs != NULL"); return
; }; }while (0)
;
169 g_return_if_fail(funcs[0] != NULL)do{ if (funcs[0] != ((void *)0)) { } else { g_return_if_fail_warning
(((gchar*) 0), __PRETTY_FUNCTION__, "funcs[0] != NULL"); return
; }; }while (0)
;
170
171 rec = expando_find(key);
172 g_return_if_fail(rec != NULL)do{ if (rec != ((void *)0)) { } else { g_return_if_fail_warning
(((gchar*) 0), __PRETTY_FUNCTION__, "rec != NULL"); return; }
; }while (0)
;
173
174 if (rec->signals == 0) {
175 /* it's unknown when this expando changes..
176 check it once in a second */
177 signal_add("expando timer", funcs[EXPANDO_ARG_NONE])signal_add_full("core", 0, ("expando timer"), (SIGNAL_FUNC) (
funcs[EXPANDO_ARG_NONE]), ((void *)0))
;
178 }
179
180 for (n = 0; n < rec->signals; n++) {
181 arg = rec->signal_args[n];
182 func = arg < funccount ? funcs[arg] : NULL((void *)0);
183 if (func == NULL((void *)0)) func = funcs[EXPANDO_ARG_NONE];
184
185 signal_add_full_id(MODULE_NAME"core", SIGNAL_PRIORITY_DEFAULT0,
186 rec->signal_ids[n], func, NULL((void *)0));
187 }
188}
189
190void expando_unbind(const char *key, int funccount, SIGNAL_FUNC *funcs)
191{
192 SIGNAL_FUNC func;
193 EXPANDO_REC *rec;
194 int n, arg;
195
196 g_return_if_fail(key != NULL)do{ if (key != ((void *)0)) { } else { g_return_if_fail_warning
(((gchar*) 0), __PRETTY_FUNCTION__, "key != NULL"); return; }
; }while (0)
;
197 g_return_if_fail(funccount >= 1)do{ if (funccount >= 1) { } else { g_return_if_fail_warning
(((gchar*) 0), __PRETTY_FUNCTION__, "funccount >= 1"); return
; }; }while (0)
;
198 g_return_if_fail(funcs != NULL)do{ if (funcs != ((void *)0)) { } else { g_return_if_fail_warning
(((gchar*) 0), __PRETTY_FUNCTION__, "funcs != NULL"); return
; }; }while (0)
;
199 g_return_if_fail(funcs[0] != NULL)do{ if (funcs[0] != ((void *)0)) { } else { g_return_if_fail_warning
(((gchar*) 0), __PRETTY_FUNCTION__, "funcs[0] != NULL"); return
; }; }while (0)
;
200
201 rec = expando_find(key);
202 g_return_if_fail(rec != NULL)do{ if (rec != ((void *)0)) { } else { g_return_if_fail_warning
(((gchar*) 0), __PRETTY_FUNCTION__, "rec != NULL"); return; }
; }while (0)
;
203
204 if (rec->signals == 0) {
205 /* it's unknown when this expando changes..
206 check it once in a second */
207 signal_remove("expando timer", funcs[EXPANDO_ARG_NONE])signal_remove_full(("expando timer"), (SIGNAL_FUNC) (funcs[EXPANDO_ARG_NONE
]), ((void *)0))
;
208 }
209
210 for (n = 0; n < rec->signals; n++) {
211 arg = rec->signal_args[n];
212 func = arg < funccount ? funcs[arg] : NULL((void *)0);
213 if (func == NULL((void *)0)) func = funcs[EXPANDO_ARG_NONE];
214
215 signal_remove_id(rec->signal_ids[n], func, NULL((void *)0));
216 }
217}
218
219/* Returns [<signal id>, EXPANDO_ARG_xxx, <signal id>, ..., -1] */
220int *expando_get_signals(const char *key)
221{
222 EXPANDO_REC *rec;
223 int *signals;
224 int n;
225
226 g_return_val_if_fail(key != NULL, NULL)do{ if (key != ((void *)0)) { } else { g_return_if_fail_warning
(((gchar*) 0), __PRETTY_FUNCTION__, "key != NULL"); return (
((void *)0)); }; }while (0)
;
227
228 rec = expando_find(key);
229 if (rec == NULL((void *)0) || rec->signals < 0)
230 return NULL((void *)0);
231
232 if (rec->signals == 0) {
233 /* it's unknown when this expando changes..
234 check it once in a second */
235 signals = g_new(int, 3)((int *) g_malloc (((gsize) sizeof (int)) * ((gsize) (3))));
236 signals[0] = signal_get_uniq_id("expando timer")module_get_uniq_id_str("signals", "expando timer");
237 signals[1] = EXPANDO_ARG_NONE;
238 signals[2] = -1;
239 return signals;
240 }
241
242 signals = g_new(int, rec->signals*2+1)((int *) g_malloc (((gsize) sizeof (int)) * ((gsize) (rec->
signals*2 +1))))
;
243 for (n = 0; n < rec->signals; n++) {
244 signals[n*2] = rec->signal_ids[n];
245 signals[n*2+1] = rec->signal_args[n];
246 }
247 signals[rec->signals*2] = -1;
248 return signals;
249}
250
251EXPANDO_FUNC expando_find_char(char chr)
252{
253 return CHAR_EXPANDO(chr)(char_expandos[(int) (unsigned char) chr]) == NULL((void *)0) ? NULL((void *)0) :
254 CHAR_EXPANDO(chr)(char_expandos[(int) (unsigned char) chr])->func;
255}
256
257EXPANDO_FUNC expando_find_long(const char *key)
258{
259 EXPANDO_REC *rec = g_hash_table_lookup(expandos, key);
260 return rec == NULL((void *)0) ? NULL((void *)0) : rec->func;
261}
262
263static gboolean free_expando(gpointer key, gpointer value, gpointer user_data)
264{
265 g_free(key);
266 g_free(value);
267 return TRUE(!(0));
268}
269
270/* last person who sent you a MSG */
271static char *expando_lastmsg(SERVER_REC *server, void *item, int *free_ret)
272{
273 return last_privmsg_from;
274}
275
276/* last person to whom you sent a MSG */
277static char *expando_lastmymsg(SERVER_REC *server, void *item, int *free_ret)
278{
279 return last_sent_msg;
280}
281
282/* last person to send a public message to a channel you are on */
283static char *expando_lastpublic(SERVER_REC *server, void *item, int *free_ret)
284{
285 return last_public_from;
286}
287
288/* text of your AWAY message, if any */
289static char *expando_awaymsg(SERVER_REC *server, void *item, int *free_ret)
290{
291 return server == NULL((void *)0) ? "" : server->away_reason;
292}
293
294/* body of last MSG you sent */
295static char *expando_lastmymsg_body(SERVER_REC *server, void *item, int *free_ret)
296{
297 return last_sent_msg_body;
298}
299
300/* current channel */
301static char *expando_channel(SERVER_REC *server, void *item, int *free_ret)
302{
303 return !IS_CHANNEL(item)(((CHANNEL_REC *) module_check_cast_module(item, __builtin_offsetof
(CHANNEL_REC, type), "WINDOW ITEM TYPE", "CHANNEL")) ? (!(0))
: (0))
? NULL((void *)0) : CHANNEL(item)((CHANNEL_REC *) module_check_cast_module(item, __builtin_offsetof
(CHANNEL_REC, type), "WINDOW ITEM TYPE", "CHANNEL"))
->name;
304}
305
306/* time client was started, $time() format */
307static char *expando_clientstarted(SERVER_REC *server, void *item, int *free_ret)
308{
309 *free_ret = TRUE(!(0));
310 return g_strdup_printf("%ld", (long) client_start_time);
311}
312
313/* channel you were last INVITEd to */
314static char *expando_last_invite(SERVER_REC *server, void *item, int *free_ret)
315{
316 return server == NULL((void *)0) ? "" : server->last_invite;
317}
318
319/* client version text string */
320static char *expando_version(SERVER_REC *server, void *item, int *free_ret)
321{
322 return PACKAGE_VERSION"0.8.13-svn";
323}
324
325/* current value of CMDCHARS */
326static char *expando_cmdchars(SERVER_REC *server, void *item, int *free_ret)
327{
328 return (char *) settings_get_str("cmdchars");
329}
330
331/* first CMDCHAR */
332static char *expando_cmdchar(SERVER_REC *server, void *item, int *free_ret)
333{
334 char str[2] = { 0, 0 };
335
336 str[0] = *settings_get_str("cmdchars");
337
338 *free_ret = TRUE(!(0));
339 return g_strdup(str);
340}
341
342/* modes of current channel, if any */
343static char *expando_chanmode(SERVER_REC *server, void *item, int *free_ret)
344{
345 char *cmode;
346 char *args;
347
348 *free_ret = FALSE(0);
349
350 if (!IS_CHANNEL(item)(((CHANNEL_REC *) module_check_cast_module(item, __builtin_offsetof
(CHANNEL_REC, type), "WINDOW ITEM TYPE", "CHANNEL")) ? (!(0))
: (0))
)
351 return NULL((void *)0);
352
353 if (!settings_get_bool("chanmode_expando_strip"))
354 return CHANNEL(item)((CHANNEL_REC *) module_check_cast_module(item, __builtin_offsetof
(CHANNEL_REC, type), "WINDOW ITEM TYPE", "CHANNEL"))
->mode;
355
356 *free_ret = TRUE(!(0));
357 cmode = g_strdup(CHANNEL(item)((CHANNEL_REC *) module_check_cast_module(item, __builtin_offsetof
(CHANNEL_REC, type), "WINDOW ITEM TYPE", "CHANNEL"))
->mode);
358 args = strchr(cmode, ' ');
359 if (args != NULL((void *)0))
360 *args = 0;
361
362 return cmode;
363}
364
365/* current nickname */
366static char *expando_nick(SERVER_REC *server, void *item, int *free_ret)
367{
368 return server == NULL((void *)0) ? "" : server->nick;
369}
370
371/* value of STATUS_OPER if you are an irc operator */
372static char *expando_statusoper(SERVER_REC *server, void *item, int *free_ret)
373{
374 return server == NULL((void *)0) || !server->server_operator ? "" :
375 (char *) settings_get_str("STATUS_OPER");
376}
377
378/* if you are a channel operator in $C, expands to a '@' */
379static char *expando_chanop(SERVER_REC *server, void *item, int *free_ret)
380{
381 return IS_CHANNEL(item)(((CHANNEL_REC *) module_check_cast_module(item, __builtin_offsetof
(CHANNEL_REC, type), "WINDOW ITEM TYPE", "CHANNEL")) ? (!(0))
: (0))
&& CHANNEL(item)((CHANNEL_REC *) module_check_cast_module(item, __builtin_offsetof
(CHANNEL_REC, type), "WINDOW ITEM TYPE", "CHANNEL"))
->chanop ? "@" : "";
382}
383
384/* nickname of whomever you are QUERYing */
385static char *expando_query(SERVER_REC *server, void *item, int *free_ret)
386{
387 return !IS_QUERY(item)(((QUERY_REC *) module_check_cast_module(item, __builtin_offsetof
(QUERY_REC, type), "WINDOW ITEM TYPE", "QUERY")) ? (!(0)) : (
0))
? "" : QUERY(item)((QUERY_REC *) module_check_cast_module(item, __builtin_offsetof
(QUERY_REC, type), "WINDOW ITEM TYPE", "QUERY"))
->name;
388}
389
390/* version of current server */
391static char *expando_serverversion(SERVER_REC *server, void *item, int *free_ret)
392{
393 return server == NULL((void *)0) ? "" : server->version;
394}
395
396/* target of current input (channel or QUERY nickname) */
397static char *expando_target(SERVER_REC *server, void *item, int *free_ret)
398{
399 return item == NULL((void *)0) ? "" :
400 (char *) window_item_get_target((WI_ITEM_REC *) item)(((WI_ITEM_REC *) item)->get_target((WI_ITEM_REC *) item));
401}
402
403/* client release date (in YYYYMMDD format) */
404static char *expando_releasedate(SERVER_REC *server, void *item, int *free_ret)
405{
406 *free_ret = TRUE(!(0));
407 return g_strdup_printf("%d", IRSSI_VERSION_DATE20090227);
408}
409
410/* client release time (in HHMM format) */
411static char *expando_releasetime(SERVER_REC *server, void *item, int *free_ret)
412{
413 *free_ret = TRUE(!(0));
414 return g_strdup_printf("%04d", IRSSI_VERSION_TIME1532);
415}
416
417/* current working directory */
418static char *expando_workdir(SERVER_REC *server, void *item, int *free_ret)
419{
420 *free_ret = TRUE(!(0));
421 return g_get_current_dir();
422}
423
424/* value of REALNAME */
425static char *expando_realname(SERVER_REC *server, void *item, int *free_ret)
426{
427 return server == NULL((void *)0) ? "" : server->connrec->realname;
428}
429
430/* time of day (hh:mm) */
431static char *expando_time(SERVER_REC *server, void *item, int *free_ret)
432{
433 time_t now;
434 struct tm *tm;
435 char str[256];
436
437 now = time(NULL((void *)0));
438 tm = localtime(&now);
439
440 if (strftime(str, sizeof(str), timestamp_format, tm) == 0)
441 return "";
442
443 *free_ret = TRUE(!(0));
444 return g_strdup(str);
445}
446
447/* a literal '$' */
448static char *expando_dollar(SERVER_REC *server, void *item, int *free_ret)
449{
450 return "$";
451}
452
453/* system name */
454static char *expando_sysname(SERVER_REC *server, void *item, int *free_ret)
455{
456 return sysname;
457}
458
459/* system release */
460static char *expando_sysrelease(SERVER_REC *server, void *item, int *free_ret)
461{
462 return sysrelease;
463}
464
465/* system architecture */
466static char *expando_sysarch(SERVER_REC *server, void *item, int *free_ret)
467{
468 return sysarch;
469}
470
471/* Topic of active channel (or address of queried nick) */
472static char *expando_topic(SERVER_REC *server, void *item, int *free_ret)
473{
474 if (IS_CHANNEL(item)(((CHANNEL_REC *) module_check_cast_module(item, __builtin_offsetof
(CHANNEL_REC, type), "WINDOW ITEM TYPE", "CHANNEL")) ? (!(0))
: (0))
)
475 return CHANNEL(item)((CHANNEL_REC *) module_check_cast_module(item, __builtin_offsetof
(CHANNEL_REC, type), "WINDOW ITEM TYPE", "CHANNEL"))
->topic;
476 if (IS_QUERY(item)(((QUERY_REC *) module_check_cast_module(item, __builtin_offsetof
(QUERY_REC, type), "WINDOW ITEM TYPE", "QUERY")) ? (!(0)) : (
0))
) {
477 QUERY_REC *query = QUERY(item)((QUERY_REC *) module_check_cast_module(item, __builtin_offsetof
(QUERY_REC, type), "WINDOW ITEM TYPE", "QUERY"))
;
478
479 if (query->server_tag == NULL((void *)0))
480 return "";
481
482 *free_ret = TRUE(!(0));
483 return query->address == NULL((void *)0) ?
484 g_strdup_printf("(%s)", query->server_tag) :
485 g_strdup_printf("%s (%s)", query->address,
486 query->server_tag);
487 }
488 return "";
489}
490
491/* Server tag */
492static char *expando_servertag(SERVER_REC *server, void *item, int *free_ret)
493{
494 return server == NULL((void *)0) ? "" : server->tag;
495}
496
497/* Server chatnet */
498static char *expando_chatnet(SERVER_REC *server, void *item, int *free_ret)
499{
500 return server == NULL((void *)0) ? "" : server->connrec->chatnet;
501}
502
503/* visible_name of current window item */
504static char *expando_itemname(SERVER_REC *server, void *item, int *free_ret)
505{
506 return item == NULL((void *)0) ? "" : ((WI_ITEM_REC *) item)->visible_name;
507}
508
509static void sig_message_public(SERVER_REC *server, const char *msg,
510 const char *nick, const char *address,
511 const char *target)
512{
513 g_free_not_null(last_public_from)g_free(last_public_from);
514 last_public_from = g_strdup(nick);
515}
516
517static void sig_message_private(SERVER_REC *server, const char *msg,
518 const char *nick, const char *address)
519{
520 g_free_not_null(last_privmsg_from)g_free(last_privmsg_from);
521 last_privmsg_from = g_strdup(nick);
522}
523
524static void sig_message_own_private(SERVER_REC *server, const char *msg,
525 const char *target, const char *origtarget)
526{
527 g_return_if_fail(server != NULL)do{ if (server != ((void *)0)) { } else { g_return_if_fail_warning
(((gchar*) 0), __PRETTY_FUNCTION__, "server != NULL"); return
; }; }while (0)
;
528 g_return_if_fail(msg != NULL)do{ if (msg != ((void *)0)) { } else { g_return_if_fail_warning
(((gchar*) 0), __PRETTY_FUNCTION__, "msg != NULL"); return; }
; }while (0)
;
529
530 if (target != NULL((void *)0)) {
531 if (target != last_sent_msg) {
532 g_free_not_null(last_sent_msg)g_free(last_sent_msg);
533 last_sent_msg = g_strdup(target);
534 }
535 g_free_not_null(last_sent_msg_body)g_free(last_sent_msg_body);
536 last_sent_msg_body = g_strdup(msg);
537 }
538}
539
540static int sig_timer(void)
541{
542 time_t now;
543 struct tm *tm;
544 int last_min;
545
546 signal_emit("expando timer", 0);
547
548 /* check if $Z has changed */
549 now = time(NULL((void *)0));
550 if (last_timestamp != now) {
551 if (!timestamp_seconds && last_timestamp != 0) {
552 /* assume it changes every minute */
553 tm = localtime(&last_timestamp);
554 last_min = tm->tm_min;
555
556 tm = localtime(&now);
557 if (tm->tm_min == last_min)
558 return 1;
559 }
560
561 signal_emit("time changed", 0);
562 last_timestamp = now;
563 }
564
565 return 1;
566}
567
568static void read_settings(void)
569{
570 timestamp_format = settings_get_str("timestamp_format");
571 timestamp_seconds =
572 strstr(timestamp_format, "%r") != NULL((void *)0) ||
573 strstr(timestamp_format, "%s") != NULL((void *)0) ||
574 strstr(timestamp_format, "%S") != NULL((void *)0) ||
575 strstr(timestamp_format, "%X") != NULL((void *)0) ||
576 strstr(timestamp_format, "%T") != NULL((void *)0);
577
578}
579
580void expandos_init(void)
581{
582#ifdef HAVE_SYS_UTSNAME_H1
583 struct utsname un;
584#endif
585 settings_add_str("misc", "STATUS_OPER", "*")settings_add_str_module("core", "misc", "STATUS_OPER", "*");
586 settings_add_str("lookandfeel", "timestamp_format", "%H:%M")settings_add_str_module("core", "lookandfeel", "timestamp_format"
, "%H:%M")
;
587 settings_add_bool("lookandfeel", "chanmode_expando_strip", FALSE)settings_add_bool_module("core", "lookandfeel", "chanmode_expando_strip"
, (0))
;
588
589 last_sent_msg = NULL((void *)0); last_sent_msg_body = NULL((void *)0);
590 last_privmsg_from = NULL((void *)0); last_public_from = NULL((void *)0);
591 last_timestamp = 0;
592
593 sysname = sysrelease = sysarch = NULL((void *)0);
594#ifdef HAVE_SYS_UTSNAME_H1
595 if (uname(&un) >= 0) {
596 sysname = g_strdup(un.sysname);
597 sysrelease = g_strdup(un.release);
598 sysarch = g_strdup(un.machine);
599 }
600#endif
601
602 memset(char_expandos, 0, sizeof(char_expandos));
603 expandos = g_hash_table_new((GHashFunc) g_str_hash,
604 (GCompareFunc) g_str_equal);
605
606 expando_create(",", expando_lastmsg,
607 "message private", EXPANDO_ARG_SERVER, NULL((void *)0));
608 expando_create(".", expando_lastmymsg,
609 "command msg", EXPANDO_ARG_NONE, NULL((void *)0));
610 expando_create(";", expando_lastpublic,
611 "message public", EXPANDO_ARG_SERVER, NULL((void *)0));
612 expando_create("A", expando_awaymsg,
613 "away mode changed", EXPANDO_ARG_NONE, NULL((void *)0));
614 expando_create("B", expando_lastmymsg_body,
615 "command msg", EXPANDO_ARG_NONE, NULL((void *)0));
616 expando_create("C", expando_channel,
617 "window changed", EXPANDO_ARG_NONE,
618 "window item changed", EXPANDO_ARG_WINDOW, NULL((void *)0));
619 expando_create("F", expando_clientstarted,
620 "", EXPANDO_NEVER, NULL((void *)0));
621 expando_create("I", expando_last_invite, NULL((void *)0));
622 expando_create("J", expando_version,
623 "", EXPANDO_NEVER, NULL((void *)0));
624 expando_create("K", expando_cmdchars,
625 "setup changed", EXPANDO_ARG_NONE, NULL((void *)0));
626 expando_create("k", expando_cmdchar,
627 "setup changed", EXPANDO_ARG_NONE, NULL((void *)0));
628 expando_create("M", expando_chanmode,
629 "window changed", EXPANDO_ARG_NONE,
630 "window item changed", EXPANDO_ARG_WINDOW,
631 "channel mode changed", EXPANDO_ARG_WINDOW_ITEM, NULL((void *)0));
632 expando_create("N", expando_nick,
633 "window changed", EXPANDO_ARG_NONE,
634 "window connect changed", EXPANDO_ARG_WINDOW,
635 "window server changed", EXPANDO_ARG_WINDOW,
636 "server nick changed", EXPANDO_ARG_SERVER, NULL((void *)0));
637 expando_create("O", expando_statusoper,
638 "setup changed", EXPANDO_ARG_NONE,
639 "window changed", EXPANDO_ARG_NONE,
640 "window server changed", EXPANDO_ARG_WINDOW,
641 "user mode changed", EXPANDO_ARG_WINDOW, NULL((void *)0));
642 expando_create("P", expando_chanop,
643 "window changed", EXPANDO_ARG_NONE,
644 "window item changed", EXPANDO_ARG_WINDOW,
645 "nick mode changed", EXPANDO_ARG_WINDOW_ITEM, NULL((void *)0));
646 expando_create("Q", expando_query,
647 "window changed", EXPANDO_ARG_NONE,
648 "window item changed", EXPANDO_ARG_WINDOW, NULL((void *)0));
649 expando_create("R", expando_serverversion,
650 "window changed", EXPANDO_ARG_NONE,
651 "window server changed", EXPANDO_ARG_WINDOW, NULL((void *)0));
652 expando_create("T", expando_target,
653 "window changed", EXPANDO_ARG_NONE,
654 "window item changed", EXPANDO_ARG_WINDOW, NULL((void *)0));
655 expando_create("V", expando_releasedate,
656 "", EXPANDO_NEVER, NULL((void *)0));
657 expando_create("versiontime", expando_releasetime,
658 "", EXPANDO_NEVER, NULL((void *)0));
659 expando_create("W", expando_workdir, NULL((void *)0));
660 expando_create("Y", expando_realname,
661 "window changed", EXPANDO_ARG_NONE,
662 "window connect changed", EXPANDO_ARG_WINDOW,
663 "window server changed", EXPANDO_ARG_WINDOW, NULL((void *)0));
664 expando_create("Z", expando_time,
665 "time changed", EXPANDO_ARG_NONE, NULL((void *)0));
666 expando_create("$", expando_dollar,
667 "", EXPANDO_NEVER, NULL((void *)0));
668
669 expando_create("sysname", expando_sysname,
670 "", EXPANDO_NEVER, NULL((void *)0));
671 expando_create("sysrelease", expando_sysrelease,
672 "", EXPANDO_NEVER, NULL((void *)0));
673 expando_create("sysarch", expando_sysarch,
674 "", EXPANDO_NEVER, NULL((void *)0));
675 expando_create("topic", expando_topic,
676 "window changed", EXPANDO_ARG_NONE,
677 "window item changed", EXPANDO_ARG_WINDOW,
678 "channel topic changed", EXPANDO_ARG_WINDOW_ITEM,
679 "query address changed", EXPANDO_ARG_WINDOW_ITEM, NULL((void *)0));
680 expando_create("tag", expando_servertag,
681 "window changed", EXPANDO_ARG_NONE,
682 "window connect changed", EXPANDO_ARG_WINDOW,
683 "window server changed", EXPANDO_ARG_WINDOW, NULL((void *)0));
684 expando_create("chatnet", expando_chatnet,
685 "window changed", EXPANDO_ARG_NONE,
686 "window connect changed", EXPANDO_ARG_WINDOW,
687 "window server changed", EXPANDO_ARG_WINDOW, NULL((void *)0));
688 expando_create("itemname", expando_itemname,
689 "window changed", EXPANDO_ARG_NONE,
690 "window item changed", EXPANDO_ARG_WINDOW,
691 "window item name changed", EXPANDO_ARG_WINDOW_ITEM,
692 NULL((void *)0));
693
694 read_settings();
695
696 timer_tag = g_timeout_add(5000, (GSourceFunc) sig_timer, NULL((void *)0));
697 signal_add("message public", (SIGNAL_FUNC) sig_message_public)signal_add_full("core", 0, ("message public"), (SIGNAL_FUNC) (
(SIGNAL_FUNC) sig_message_public), ((void *)0))
;
698 signal_add("message private", (SIGNAL_FUNC) sig_message_private)signal_add_full("core", 0, ("message private"), (SIGNAL_FUNC)
((SIGNAL_FUNC) sig_message_private), ((void *)0))
;
699 signal_add("message own_private", (SIGNAL_FUNC) sig_message_own_private)signal_add_full("core", 0, ("message own_private"), (SIGNAL_FUNC
) ((SIGNAL_FUNC) sig_message_own_private), ((void *)0))
;
700 signal_add_first("setup changed", (SIGNAL_FUNC) read_settings)signal_add_full("core", -100, ("setup changed"), (SIGNAL_FUNC
) ((SIGNAL_FUNC) read_settings), ((void *)0))
;
701}
702
703void expandos_deinit(void)
704{
705 int n;
706
707 for (n = 0; n < sizeof(char_expandos)/sizeof(char_expandos[0]); n++)
708 g_free_not_null(char_expandos[n])g_free(char_expandos[n]);
709
710 g_hash_table_foreach_remove(expandos, free_expando, NULL((void *)0));
711 g_hash_table_destroy(expandos);
712
713 g_free_not_null(last_sent_msg)g_free(last_sent_msg); g_free_not_null(last_sent_msg_body)g_free(last_sent_msg_body);
714 g_free_not_null(last_privmsg_from)g_free(last_privmsg_from); g_free_not_null(last_public_from)g_free(last_public_from);
715 g_free_not_null(sysname)g_free(sysname); g_free_not_null(sysrelease)g_free(sysrelease);
716 g_free_not_null(sysarch)g_free(sysarch);
717
718 g_source_remove(timer_tag);
719 signal_remove("message public", (SIGNAL_FUNC) sig_message_public)signal_remove_full(("message public"), (SIGNAL_FUNC) ((SIGNAL_FUNC
) sig_message_public), ((void *)0))
;
720 signal_remove("message private", (SIGNAL_FUNC) sig_message_private)signal_remove_full(("message private"), (SIGNAL_FUNC) ((SIGNAL_FUNC
) sig_message_private), ((void *)0))
;
721 signal_remove("message own_private", (SIGNAL_FUNC) sig_message_own_private)signal_remove_full(("message own_private"), (SIGNAL_FUNC) ((SIGNAL_FUNC
) sig_message_own_private), ((void *)0))
;
722 signal_remove("setup changed", (SIGNAL_FUNC) read_settings)signal_remove_full(("setup changed"), (SIGNAL_FUNC) ((SIGNAL_FUNC
) read_settings), ((void *)0))
;
723}