1 /*
2 server-idle.c : irssi
3
4 Copyright (C) 1999-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 "module.h"
22 #include "signals.h"
23
24 #include "irc-servers.h"
25 #include "servers-idle.h"
26 #include "servers-redirect.h"
27
28 typedef struct {
29 char *cmd;
30 char *arg;
31 int tag;
32
33 char *redirect_cmd;
34 int count;
35 int remote;
36 char *failure_signal;
37 GSList *redirects;
38 } SERVER_IDLE_REC;
39
40 static int idle_tag, idlepos;
41
42 /* Add new idle command to queue */
43 static SERVER_IDLE_REC *
server_idle_create(const char * cmd,const char * redirect_cmd,int count,const char * arg,int remote,const char * failure_signal,va_list va)44 server_idle_create(const char *cmd, const char *redirect_cmd, int count,
45 const char *arg, int remote, const char *failure_signal,
46 va_list va)
47 {
48 SERVER_IDLE_REC *rec;
49 const char *event, *signal;
50
51 g_return_val_if_fail(cmd != NULL, FALSE);
52
53 rec = g_new0(SERVER_IDLE_REC, 1);
54 rec->cmd = g_strdup(cmd);
55 rec->arg = g_strdup(arg);
56 rec->tag = ++idlepos;
57
58 rec->redirect_cmd = g_strdup(redirect_cmd);
59 rec->count = count;
60 rec->remote = remote;
61 rec->failure_signal = g_strdup(failure_signal);
62
63 while ((event = va_arg(va, const char *)) != NULL) {
64 signal = va_arg(va, const char *);
65 if (signal == NULL) {
66 g_warning("server_idle_create(%s): "
67 "signal not specified for event",
68 redirect_cmd);
69 break;
70 }
71
72 rec->redirects =
73 g_slist_append(rec->redirects, g_strdup(event));
74 rec->redirects =
75 g_slist_append(rec->redirects, g_strdup(signal));
76 }
77
78 return rec;
79 }
80
server_idle_find_rec(IRC_SERVER_REC * server,int tag)81 static SERVER_IDLE_REC *server_idle_find_rec(IRC_SERVER_REC *server, int tag)
82 {
83 GSList *tmp;
84
85 g_return_val_if_fail(server != NULL, FALSE);
86
87 for (tmp = server->idles; tmp != NULL; tmp = tmp->next) {
88 SERVER_IDLE_REC *rec = tmp->data;
89
90 if (rec->tag == tag)
91 return rec;
92 }
93
94 return NULL;
95 }
96
97 /* Add new idle command to queue */
server_idle_add_redir(IRC_SERVER_REC * server,const char * cmd,const char * redirect_cmd,int count,const char * arg,int remote,const char * failure_signal,...)98 int server_idle_add_redir(IRC_SERVER_REC *server, const char *cmd,
99 const char *redirect_cmd, int count, const char *arg,
100 int remote, const char *failure_signal, ...)
101 {
102 va_list va;
103 SERVER_IDLE_REC *rec;
104
105 g_return_val_if_fail(server != NULL, -1);
106
107 va_start(va, failure_signal);
108 rec = server_idle_create(cmd, redirect_cmd, count, arg, remote,
109 failure_signal, va);
110 server->idles = g_slist_append(server->idles, rec);
111 va_end(va);
112
113 return rec->tag;
114 }
115
116 /* Add new idle command to first of queue */
server_idle_add_first_redir(IRC_SERVER_REC * server,const char * cmd,const char * redirect_cmd,int count,const char * arg,int remote,const char * failure_signal,...)117 int server_idle_add_first_redir(IRC_SERVER_REC *server, const char *cmd,
118 const char *redirect_cmd, int count,
119 const char *arg, int remote,
120 const char *failure_signal, ...)
121 {
122 va_list va;
123 SERVER_IDLE_REC *rec;
124
125 g_return_val_if_fail(server != NULL, -1);
126
127 va_start(va, failure_signal);
128 rec = server_idle_create(cmd, redirect_cmd, count, arg, remote,
129 failure_signal, va);
130 server->idles = g_slist_prepend(server->idles, rec);
131 va_end(va);
132
133 return rec->tag;
134 }
135
136 /* Add new idle command to specified position of queue */
server_idle_insert_redir(IRC_SERVER_REC * server,const char * cmd,int tag,const char * redirect_cmd,int count,const char * arg,int remote,const char * failure_signal,...)137 int server_idle_insert_redir(IRC_SERVER_REC *server, const char *cmd, int tag,
138 const char *redirect_cmd, int count,
139 const char *arg, int remote,
140 const char *failure_signal, ...)
141 {
142 va_list va;
143 SERVER_IDLE_REC *rec;
144 int pos;
145
146 g_return_val_if_fail(server != NULL, -1);
147
148 va_start(va, failure_signal);
149
150 /* find the position of tag in idle list */
151 rec = server_idle_find_rec(server, tag);
152 pos = g_slist_index(server->idles, rec);
153
154 rec = server_idle_create(cmd, redirect_cmd, count, arg, remote,
155 failure_signal, va);
156 server->idles = pos < 0 ?
157 g_slist_append(server->idles, rec) :
158 g_slist_insert(server->idles, rec, pos);
159 va_end(va);
160
161 return rec->tag;
162 }
163
server_idle_destroy(IRC_SERVER_REC * server,SERVER_IDLE_REC * rec)164 static void server_idle_destroy(IRC_SERVER_REC *server, SERVER_IDLE_REC *rec)
165 {
166 g_return_if_fail(server != NULL);
167
168 server->idles = g_slist_remove(server->idles, rec);
169
170 g_slist_foreach(rec->redirects, (GFunc) g_free, NULL);
171 g_slist_free(rec->redirects);
172
173 g_free_not_null(rec->arg);
174 g_free_not_null(rec->redirect_cmd);
175 g_free_not_null(rec->failure_signal);
176 g_free(rec->cmd);
177 g_free(rec);
178 }
179
180 /* Check if record is still in queue */
server_idle_find(IRC_SERVER_REC * server,int tag)181 int server_idle_find(IRC_SERVER_REC *server, int tag)
182 {
183 return server_idle_find_rec(server, tag) != NULL;
184 }
185
186 /* Remove record from idle queue */
server_idle_remove(IRC_SERVER_REC * server,int tag)187 int server_idle_remove(IRC_SERVER_REC *server, int tag)
188 {
189 SERVER_IDLE_REC *rec;
190
191 g_return_val_if_fail(server != NULL, FALSE);
192
193 rec = server_idle_find_rec(server, tag);
194 if (rec == NULL)
195 return FALSE;
196
197 server_idle_destroy(server, rec);
198 return TRUE;
199 }
200
201 /* Execute next idle command */
server_idle_next(IRC_SERVER_REC * server)202 static void server_idle_next(IRC_SERVER_REC *server)
203 {
204 SERVER_IDLE_REC *rec;
205
206 g_return_if_fail(server != NULL);
207
208 if (server->idles == NULL)
209 return;
210 rec = server->idles->data;
211
212 /* Send command */
213 if (rec->redirect_cmd != NULL) {
214 server_redirect_event_list(server, rec->redirect_cmd,
215 rec->count, rec->arg,
216 rec->remote, rec->failure_signal,
217 rec->redirects);
218 }
219 irc_send_cmd(server, rec->cmd);
220
221 server_idle_destroy(server, rec);
222 }
223
sig_disconnected(IRC_SERVER_REC * server)224 static void sig_disconnected(IRC_SERVER_REC *server)
225 {
226 g_return_if_fail(server != NULL);
227
228 if (!IS_IRC_SERVER(server))
229 return;
230
231 while (server->idles != NULL)
232 server_idle_destroy(server, server->idles->data);
233 }
234
sig_idle_timeout(void)235 static int sig_idle_timeout(void)
236 {
237 GSList *tmp;
238
239 /* Scan through every server */
240 for (tmp = servers; tmp != NULL; tmp = tmp->next) {
241 IRC_SERVER_REC *rec = tmp->data;
242
243 if (IS_IRC_SERVER(rec) &&
244 rec->idles != NULL && rec->cmdcount == 0) {
245 /* We're idling and we have idle commands to run! */
246 server_idle_next(rec);
247 }
248 }
249 return 1;
250 }
251
servers_idle_init(void)252 void servers_idle_init(void)
253 {
254 idlepos = 0;
255 idle_tag = g_timeout_add(1000, (GSourceFunc) sig_idle_timeout, NULL);
256
257 signal_add("server disconnected", (SIGNAL_FUNC) sig_disconnected);
258 }
259
servers_idle_deinit(void)260 void servers_idle_deinit(void)
261 {
262 g_source_remove(idle_tag);
263 signal_remove("server disconnected", (SIGNAL_FUNC) sig_disconnected);
264 }
265