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... */