Mercurial > ~mikael > mcabber > hg
comparison mcabber/mcabber/events.c @ 1685:1342df44c814
Improved events interface
* User can pass additional arguments to event handler
* MUC invitation reject now can be supplied a reason
author | Myhailo Danylenko <isbear@ukrpost.net> |
---|---|
date | Tue, 02 Feb 2010 22:44:18 +0100 |
parents | 41c26b7d2890 |
children | e6e89b1d7831 |
comparison
equal
deleted
inserted
replaced
1684:95df4ea512c8 | 1685:1342df44c814 |
---|---|
1 /* | 1 /* |
2 * events.c -- Events fonctions | 2 * events.c -- Events fonctions |
3 * | 3 * |
4 * Copyright (C) 2006-2009 Mikael Berthe <mikael@lilotux.net> | 4 * Copyright (C) 2006-2009 Mikael Berthe <mikael@lilotux.net> |
5 * Copyrigth (C) 2010 Myhailo Danylenko <isbear@ukrposte.net> | |
5 * | 6 * |
6 * This program is free software; you can redistribute it and/or modify | 7 * 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 * 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 (at | 9 * the Free Software Foundation; either version 2 of the License, or (at |
9 * your option) any later version. | 10 * your option) any later version. |
22 #include <glib.h> | 23 #include <glib.h> |
23 #include <string.h> | 24 #include <string.h> |
24 #include "events.h" | 25 #include "events.h" |
25 #include "logprint.h" | 26 #include "logprint.h" |
26 | 27 |
28 typedef struct { | |
29 char *id; | |
30 char *description; | |
31 time_t timeout; | |
32 guint source; | |
33 evs_callback_t callback; | |
34 gpointer data; | |
35 GDestroyNotify notify; | |
36 } evs_t; | |
37 | |
27 static GSList *evs_list; // Events list | 38 static GSList *evs_list; // Events list |
28 | 39 |
29 static eviqs *evs_find(const char *evid); | 40 static evs_t *evs_find(const char *evid); |
41 | |
42 static gboolean evs_check_timeout (gpointer userdata) | |
43 { | |
44 evs_t *event = userdata; | |
45 if (event->callback && | |
46 !event->callback(EVS_CONTEXT_TIMEOUT, NULL, event->data)) { | |
47 evs_del(event->id); | |
48 return FALSE; | |
49 } | |
50 return TRUE; // XXX | |
51 } | |
30 | 52 |
31 // evs_new(type, timeout) | 53 // evs_new(type, timeout) |
32 // Create an events structure. | 54 // Create new event. If id is omitted, generates unique |
33 eviqs *evs_new(guint8 type, time_t timeout) | 55 // numerical id (recommended). If timeout is specified, sets |
56 // up timeout source, that will call handler in timeout | |
57 // context after specified number of seconds. If supplied id | |
58 // already exists, returns NULL, calling destroy notifier, if | |
59 // one is specified. | |
60 const char *evs_new(const char *desc, const char *id, time_t timeout, evs_callback_t callback, gpointer udata, GDestroyNotify notify) | |
34 { | 61 { |
35 static guint evs_idn; | 62 static guint evs_idn; |
36 eviqs *new_evs; | 63 evs_t *event; |
37 time_t now_t; | |
38 char *stridn; | 64 char *stridn; |
39 | 65 |
40 if (!++evs_idn) | 66 if (!id) { |
41 evs_idn = 1; | 67 if (!++evs_idn) |
42 /* Check for wrapping, we shouldn't reuse ids */ | 68 evs_idn = 1; |
43 stridn = g_strdup_printf("%d", evs_idn); | 69 /* Check for wrapping, we shouldn't reuse ids */ |
44 if (evs_find(stridn)) { | 70 stridn = g_strdup_printf("%d", evs_idn); |
45 g_free(stridn); | 71 if (evs_find(stridn)) { |
46 // We could try another id but for now giving up should be fine... | 72 g_free(stridn); |
73 // We could try another id but for now giving up should be fine... | |
74 if (notify) | |
75 notify(udata); | |
76 return NULL; | |
77 } | |
78 } else if (!evs_find(id)) | |
79 stridn = g_strdup(id); | |
80 else { | |
81 if (notify) | |
82 notify(udata); | |
47 return NULL; | 83 return NULL; |
48 } | 84 } |
49 | 85 |
50 new_evs = g_new0(eviqs, 1); | 86 event = g_new(evs_t, 1); |
51 time(&now_t); | 87 |
52 new_evs->ts_create = now_t; | 88 event->id = stridn; |
89 event->description = g_strdup(desc); | |
90 event->timeout = timeout; | |
91 event->callback = callback; | |
92 event->data = udata; | |
93 event->notify = notify; | |
94 | |
53 if (timeout) | 95 if (timeout) |
54 new_evs->ts_expire = now_t + timeout; | 96 g_timeout_add_seconds(timeout, evs_check_timeout, event); |
55 new_evs->type = type; | 97 |
56 new_evs->id = stridn; | 98 evs_list = g_slist_append(evs_list, event); |
57 | 99 return stridn; |
58 if(!g_slist_length(evs_list)) | 100 } |
59 g_timeout_add_seconds(20, evs_check_timeout, NULL); | 101 |
60 evs_list = g_slist_append(evs_list, new_evs); | 102 static evs_t *evs_find(const char *evid) |
61 return new_evs; | |
62 } | |
63 | |
64 int evs_del(const char *evid) | |
65 { | 103 { |
66 GSList *p; | 104 GSList *p; |
67 eviqs *i; | 105 |
68 | 106 if (!evid) |
69 if (!evid) return 1; | 107 return NULL; |
70 | 108 |
71 for (p = evs_list; p; p = g_slist_next(p)) { | 109 for (p = evs_list; p; p = g_slist_next(p)) { |
72 i = p->data; | 110 evs_t *i = p->data; |
73 if (!strcmp(evid, i->id)) | |
74 break; | |
75 } | |
76 if (p) { | |
77 g_free(i->id); | |
78 g_free(i->data); | |
79 g_free(i->desc); | |
80 g_free(i); | |
81 evs_list = g_slist_remove(evs_list, p->data); | |
82 return 0; // Ok, deleted | |
83 } | |
84 return -1; // Not found | |
85 } | |
86 | |
87 static eviqs *evs_find(const char *evid) | |
88 { | |
89 GSList *p; | |
90 eviqs *i; | |
91 | |
92 if (!evid) return NULL; | |
93 | |
94 for (p = evs_list; p; p = g_slist_next(p)) { | |
95 i = p->data; | |
96 if (!strcmp(evid, i->id)) | 111 if (!strcmp(evid, i->id)) |
97 return i; | 112 return i; |
98 } | 113 } |
99 return NULL; | 114 return NULL; |
100 } | 115 } |
101 | 116 |
102 // evs_callback(evid, evcontext) | 117 // evs_del(evid) |
118 // Deletes event. | |
119 // This will not call event handler, however this will | |
120 // call destroy notify function. | |
121 // Returns 0 in case of success, -1 if the evid hasn't been found. | |
122 int evs_del(const char *evid) | |
123 { | |
124 evs_t *event = evs_find(evid); | |
125 | |
126 if (!event) | |
127 return -1; | |
128 | |
129 if (event->notify) | |
130 event->notify(event->data); | |
131 if (event->source) | |
132 g_source_remove(event->source); | |
133 | |
134 evs_list = g_slist_remove(evs_list, event); | |
135 g_free(event->id); | |
136 g_free(event->description); | |
137 g_free(event); | |
138 | |
139 return 0; // Ok, deleted | |
140 } | |
141 | |
142 // evs_callback(evid, evcontext, argument) | |
103 // Callback processing for the specified event. | 143 // Callback processing for the specified event. |
144 // If event handler will return FALSE, event will be destroyed. | |
104 // Return 0 in case of success, -1 if the evid hasn't been found. | 145 // Return 0 in case of success, -1 if the evid hasn't been found. |
105 int evs_callback(const char *evid, guint evcontext) | 146 // evcontext and argument are transparently passed to event handler. |
106 { | 147 int evs_callback(const char *evid, guint context, const char *arg) |
107 eviqs *i; | 148 { |
108 | 149 evs_t *event; |
109 i = evs_find(evid); | 150 |
110 if (!i) return -1; | 151 event = evs_find(evid); |
111 | 152 if (!event) |
112 // IQ processing | 153 return -1; |
113 // Note: If xml_result is NULL, this is a timeout | 154 |
114 if (i->callback) | 155 if (event->callback && |
115 (void)(*i->callback)(i, evcontext); | 156 !event->callback(context, arg, event->data)) |
116 | 157 evs_del(evid); |
117 evs_del(evid); | |
118 return 0; | 158 return 0; |
119 } | 159 } |
120 | 160 |
121 gboolean evs_check_timeout() | 161 // evs_display_list() |
122 { | 162 // Prints list of events to mcabber log window. |
123 time_t now_t; | 163 void evs_display_list(void) |
164 { | |
124 GSList *p; | 165 GSList *p; |
125 eviqs *i; | |
126 | |
127 time(&now_t); | |
128 p = evs_list; | |
129 if (!p) | |
130 return FALSE; | |
131 while (p) { | |
132 i = p->data; | |
133 // We must get next IQ eviqs element now because the current one | |
134 // could be freed. | |
135 p = g_slist_next(p); | |
136 | |
137 if ((!i->ts_expire && now_t > i->ts_create + EVS_MAX_TIMEOUT) || | |
138 (i->ts_expire && now_t > i->ts_expire)) { | |
139 evs_callback(i->id, EVS_CONTEXT_TIMEOUT); | |
140 } | |
141 } | |
142 return TRUE; | |
143 } | |
144 | |
145 void evs_display_list(void) | |
146 { | |
147 GSList *p; | |
148 eviqs *i; | |
149 | 166 |
150 scr_LogPrint(LPRINT_LOGNORM, "Events list:"); | 167 scr_LogPrint(LPRINT_LOGNORM, "Events list:"); |
151 for (p = evs_list; p; p = g_slist_next(p)) { | 168 for (p = evs_list; p; p = g_slist_next(p)) { |
152 i = p->data; | 169 evs_t *i = p->data; |
153 scr_LogPrint(LPRINT_LOGNORM, | 170 scr_LogPrint(LPRINT_LOGNORM, |
154 "Id: %-3s %s", i->id, (i->desc ? i->desc : "")); | 171 "Id: %-3s %s", i->id, |
172 (i->description ? i->description : "")); | |
155 } | 173 } |
156 scr_LogPrint(LPRINT_LOGNORM, "End of events list."); | 174 scr_LogPrint(LPRINT_LOGNORM, "End of events list."); |
157 } | 175 } |
158 | 176 |
159 // evs_geteventslist(bool comp) | 177 // evs_geteventslist() |
160 // Return a singly-linked-list of events ids, for the completion system. | 178 // Return a singly-linked-list of events ids. |
161 // If comp is true, the string "list" is added (it's a completion argument). | 179 // Data in list should not be modified and can disappear, |
162 // Note: the caller should free the list (and data) after use. | 180 // you must strdup them, if you want them to persist. |
163 GSList *evs_geteventslist(int compl) | 181 // Note: the caller should free the list after use. |
182 GSList *evs_geteventslist(void) | |
164 { | 183 { |
165 GSList *evidlist = NULL, *p; | 184 GSList *evidlist = NULL, *p; |
166 eviqs *i; | |
167 | 185 |
168 for (p = evs_list; p; p = g_slist_next(p)) { | 186 for (p = evs_list; p; p = g_slist_next(p)) { |
169 i = p->data; | 187 evs_t *i = p->data; |
170 evidlist = g_slist_append(evidlist, g_strdup(i->id)); | 188 evidlist = g_slist_append(evidlist, i->id); |
171 } | 189 } |
172 | 190 |
173 if (compl) { | |
174 // Last item is the "list" subcommand. | |
175 evidlist = g_slist_append(evidlist, g_strdup("list")); | |
176 } | |
177 return evidlist; | 191 return evidlist; |
178 } | 192 } |
179 | 193 |
194 // evs_deinit() | |
195 // Frees all events. | |
196 void evs_deinit(void) | |
197 { | |
198 GSList *eel; | |
199 for (eel = evs_list; eel; eel = eel->next) { | |
200 evs_t *event = eel->data; | |
201 if (event->notify) | |
202 event->notify(event->data); | |
203 if (event->source) | |
204 g_source_remove(event->source); | |
205 | |
206 evs_list = g_slist_remove(evs_list, event); | |
207 g_free(event->id); | |
208 g_free(event->description); | |
209 g_free(event); | |
210 } | |
211 g_slist_free(evs_list); | |
212 evs_list = NULL; | |
213 } | |
214 | |
180 /* vim: set expandtab cindent cinoptions=>2\:2(0: For Vim users... */ | 215 /* vim: set expandtab cindent cinoptions=>2\:2(0: For Vim users... */ |