1 /*
2 * Manages the available connections (note the file is misnamed)
3 *
4 * climm Copyright (C) © 2001-2010 Rüdiger Kuhlmann
5 *
6 * climm is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 2 dated June, 1991.
9 *
10 * climm is distributed in the hope that it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
13 * License for more details.
14 *
15 * In addition, as a special exception permission is granted to link the
16 * code of this release of climm with the OpenSSL project's "OpenSSL"
17 * library, and distribute the linked executables. You must obey the GNU
18 * General Public License in all respects for all of the code used other
19 * than "OpenSSL". If you modify this file, you may extend this exception
20 * to your version of the file, but you are not obligated to do so. If you
21 * do not wish to do so, delete this exception statement from your version
22 * of this file.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this package; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27 * 02111-1307, USA.
28 *
29 * $Id: connection.c 2864 2010-03-16 22:48:25Z kuhlmann $
30 */
31
32 #include "climm.h"
33 #include "connection.h"
34 #include "preferences.h"
35 #include "util_ui.h"
36 #include "oscar_dc.h"
37 #if HAVE_NETDB_H
38 #include <netdb.h>
39 #endif
40 #if HAVE_WINSOCK2_H
41 #include <winsock2.h>
42 #endif
43 #include <assert.h>
44
45 #define ServerListLen 5
46 #define ConnectionListLen 10
47
48 typedef struct ConnectionList_s ConnectionList;
49 typedef struct ServerList_s ServerList;
50
51 struct ConnectionList_s
52 {
53 ConnectionList *more;
54 Connection *conn[ConnectionListLen];
55 };
56
57
58 struct ServerList_s
59 {
60 ServerList *more;
61 Server *serv[ServerListLen];
62 };
63
64
65 static ConnectionList clist = { NULL, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0} };
66 static ServerList slist = { NULL, {0, 0, 0, 0, 0} };
67
68 /*
69 * Creates a new session.
70 * Returns NULL if not enough memory available.
71 */
72 #undef ServerC
ServerC(UWORD type DEBUGPARAM)73 Server *ServerC (UWORD type DEBUGPARAM)
74 {
75 Connection *conn;
76 Server *serv;
77 ServerList *cl;
78 int i, j;
79
80 conn = ConnectionC (type & ~TYPEF_ANY_SERVER);
81 if (!conn)
82 return NULL;
83
84 cl = &slist;
85 i = j = 0;
86 while (cl->serv[ServerListLen - 1] && cl->more)
87 cl = cl->more, j += ServerListLen;
88 if (cl->serv[ServerListLen - 1])
89 {
90 cl->more = calloc (1, sizeof (ServerList));
91
92 if (!cl->more)
93 return NULL;
94
95 cl = cl->more;
96 j += ServerListLen;
97 }
98 while (cl->serv[i])
99 i++, j++;
100
101 if (!(serv = calloc (1, sizeof (Server))))
102 {
103 ConnectionD (conn);
104 return NULL;
105 }
106 cl->serv[i] = serv;
107
108 conn->serv = serv;
109 serv->conn = conn;
110
111 serv->logfd = -1;
112 serv->flags = 0;
113 serv->status = ims_offline;
114 assert (type & TYPEF_ANY_SERVER);
115 serv->type = type;
116
117 Debug (DEB_CONNECT, "<=S= %p create %d", serv, serv->type);
118 return serv;
119 }
120
121 /*
122 * Creates a new session.
123 * Returns NULL if not enough memory available.
124 */
125 #undef ConnectionC
ConnectionC(UWORD type DEBUGPARAM)126 Connection *ConnectionC (UWORD type DEBUGPARAM)
127 {
128 ConnectionList *cl;
129 Connection *conn;
130 int i, j;
131
132 cl = &clist;
133 i = j = 0;
134 assert (~type & TYPEF_ANY_SERVER);
135 while (cl->conn[ConnectionListLen - 1] && cl->more)
136 cl = cl->more, j += ConnectionListLen;
137 if (cl->conn[ConnectionListLen - 1])
138 {
139 cl->more = calloc (1, sizeof (ConnectionList));
140
141 if (!cl->more)
142 return NULL;
143
144 cl = cl->more;
145 j += ConnectionListLen;
146 }
147 while (cl->conn[i])
148 i++, j++;
149
150 if (!(conn = calloc (1, sizeof (Connection))))
151 return NULL;
152 cl->conn[i] = conn;
153
154 conn->our_local_ip = 0x7f000001;
155 conn->our_outside_ip = 0x7f000001;
156 conn->sok = -1;
157 conn->type = type;
158
159 Debug (DEB_CONNECT, "<=== %p[%d] create %d", conn, j, type);
160
161 return conn;
162 }
163
164 /*
165 * Clones an existing session, while blanking out some values.
166 * Returns NULL if not enough memory available.
167 */
168 #undef ServerChild
ServerChild(Server * serv,Contact * cont,UWORD type DEBUGPARAM)169 Connection *ServerChild (Server *serv, Contact *cont, UWORD type DEBUGPARAM)
170 {
171 Connection *child;
172
173 child = ConnectionC (type DEBUGFOR);
174 if (!child)
175 return NULL;
176
177 child->serv = serv;
178 child->cont = cont;
179
180 Debug (DEB_CONNECT, "<=*= %p (%s) clone from %p (%s)",
181 child, ConnectionStrType (child), serv, ServerStrType (serv));
182
183 return child;
184 }
185
186 /*
187 * Returns the n-th connection.
188 */
ConnectionNr(int i)189 Connection *ConnectionNr (int i)
190 {
191 ConnectionList *cl;
192
193 for (cl = &clist; cl && i >= ConnectionListLen; cl = cl->more)
194 i -= ConnectionListLen;
195
196 if (!cl || i < 0)
197 return NULL;
198
199 return cl->conn[i];
200 }
201
202 /*
203 * Returns the n-th session.
204 */
ServerNr(int i)205 Server *ServerNr (int i)
206 {
207 ServerList *cl;
208
209 for (cl = &slist; cl && i >= ServerListLen; cl = cl->more)
210 i -= ServerListLen;
211
212 if (!cl || i < 0)
213 return NULL;
214
215 return cl->serv[i];
216 }
217
218 /*
219 * Finds a session of given type and/or given uin.
220 * Actually, you may specify TYPEF_* here that must all be set.
221 * The parent is the session this one has to have as parent.
222 */
ServerFindChild(const Server * parent,const Contact * cont,UWORD type)223 Connection *ServerFindChild (const Server *parent, const Contact *cont, UWORD type)
224 {
225 ConnectionList *cl;
226 Connection *conn;
227 int i;
228
229 if (parent)
230 {
231 if (cont)
232 {
233 for (cl = &clist; cl; cl = cl->more)
234 for (i = 0; i < ConnectionListLen; i++)
235 if ((conn = cl->conn[i]) && (conn->type & type) == type && conn->cont == cont && conn->serv == parent)
236 return conn;
237 }
238 else
239 for (cl = &clist; cl; cl = cl->more)
240 for (i = 0; i < ConnectionListLen; i++)
241 if ((conn = cl->conn[i]) && (conn->type & type) == type && (conn->connect & CONNECT_OK) && conn->serv == parent)
242 return conn;
243 }
244 else
245 {
246 if (cont)
247 {
248 for (cl = &clist; cl; cl = cl->more)
249 for (i = 0; i < ConnectionListLen; i++)
250 if ((conn = cl->conn[i]) && (conn->type & type) == type && conn->cont == cont)
251 return conn;
252 }
253 else
254 {
255 for (cl = &clist; cl; cl = cl->more)
256 for (i = 0; i < ConnectionListLen; i++)
257 if ((conn = cl->conn[i]) && (conn->type & type) == type && (conn->connect & CONNECT_OK))
258 return conn;
259 for (cl = &clist; cl; cl = cl->more)
260 for (i = 0; i < ConnectionListLen; i++)
261 if ((conn = cl->conn[i]) && (conn->type & type) == type)
262 return conn;
263 }
264 }
265 return NULL;
266 }
267
268 /*
269 * Finds a session of given type and given screen.
270 * Actually, you may specify TYPEF_* here that must all be set.
271 */
ServerFindScreen(UWORD type,const char * screen)272 Server *ServerFindScreen (UWORD type, const char *screen)
273 {
274 ServerList *cl;
275 Server *serv;
276 int i;
277
278 assert (type);
279 assert (screen);
280 assert (type & TYPEF_ANY_SERVER);
281
282 for (cl = &slist; cl; cl = cl->more)
283 for (i = 0; i < ServerListLen; i++)
284 if ((serv = cl->serv[i]) && (serv->type & type) == type
285 && serv->screen && !strcmp (serv->screen, screen))
286 return serv;
287 return NULL;
288 }
289
290 /*
291 * Finds the index of this session.
292 */
ConnectionFindNr(const Connection * conn)293 UDWORD ConnectionFindNr (const Connection *conn)
294 {
295 ConnectionList *cl;
296 int i, j;
297
298 if (!conn)
299 return -1;
300
301 for (i = 0, cl = &clist; cl; cl = cl->more)
302 for (j = i; i < j + ConnectionListLen; i++)
303 if (cl->conn[i % ConnectionListLen] == conn)
304 return i;
305 return -1;
306 }
307
308 /*
309 * Finds the index of this session.
310 */
ServerFindNr(const Server * serv)311 UDWORD ServerFindNr (const Server *serv)
312 {
313 ServerList *cl;
314 int i, j;
315
316 if (!serv)
317 return -1;
318
319 for (i = 0, cl = &slist; cl; cl = cl->more)
320 for (j = i; i < j + ServerListLen; i++)
321 if (cl->serv[i % ServerListLen] == serv)
322 return i;
323 return -1;
324 }
325
326 /*
327 * Closes and removes a session.
328 */
329 #undef ServerD
ServerD(Server * serv DEBUGPARAM)330 void ServerD (Server *serv DEBUGPARAM)
331 {
332 ConnectionList *cl;
333 Connection *clc;
334 int j;
335
336 s_repl (&serv->screen, NULL);
337 for (cl = &clist; cl; cl = cl->more)
338 for (j = 0; j < ConnectionListLen; j++)
339 if ((clc = cl->conn[j]) && clc->serv == serv)
340 {
341 clc->serv = NULL;
342 ConnectionD (clc);
343 cl = &clist;
344 j = -1;
345 }
346
347 ConnectionD (serv->conn);
348 serv->conn = NULL;
349 free (serv);
350
351 Debug (DEB_CONNECT, "=S=> %p closed.", serv);
352 }
353
354 /*
355 * Closes and removes a session.
356 */
357 #undef ConnectionD
ConnectionD(Connection * conn DEBUGPARAM)358 void ConnectionD (Connection *conn DEBUGPARAM)
359 {
360 ConnectionList *cl;
361 Connection *clc;
362 int i, j, k;
363
364 if ((i = ConnectionFindNr (conn)) == -1)
365 return;
366
367 Debug (DEB_CONNECT, "===> %p[%d] (%s) closing...", conn, i, ConnectionStrType (conn));
368
369 UtilIOClose (conn);
370
371 if ((i = ConnectionFindNr (conn)) == -1)
372 return;
373
374 conn->sok = -1;
375 conn->connect = 0;
376 conn->serv = NULL;
377 s_free (conn->server);
378 conn->server = NULL;
379
380 for (cl = &clist; cl; cl = cl->more)
381 for (j = 0; j < ConnectionListLen; j++)
382 if ((clc = cl->conn[j]) && clc->oscar_file == conn)
383 clc->oscar_file = NULL;
384
385 QueueCancel (conn);
386
387 for (k = 0, cl = &clist; cl; cl = cl->more)
388 {
389 for (i = 0; i < ConnectionListLen; i++, k++)
390 if (cl->conn[i] == conn)
391 break;
392 if (i < ConnectionListLen)
393 break;
394 }
395
396 while (cl)
397 {
398 for (j = i; j + 1 < ConnectionListLen; j++)
399 cl->conn[j] = cl->conn[j + 1];
400 cl->conn[j] = cl->more ? cl->more->conn[0] : NULL;
401 i = 0;
402 cl = cl->more;
403 }
404
405 Debug (DEB_CONNECT, "===> %p[%d] closed.", conn, k);
406 free (conn);
407 }
408
409 /*
410 * Returns a string describing the session's type.
411 */
ConnectionStrType(Connection * conn)412 const char *ConnectionStrType (Connection *conn)
413 {
414 switch (conn->type) {
415 case TYPE_XMPP_SERVER & ~TYPEF_ANY_SERVER:
416 return i18n (2730, "xmpp main i/o");
417 case TYPE_MSN_SERVER & ~TYPEF_ANY_SERVER:
418 return i18n (2731, "msn main i/o");
419 case TYPE_SERVER & ~TYPEF_ANY_SERVER:
420 return i18n (2732, "icq main i/o");
421 case TYPE_MSN_TEMP:
422 return i18n (2584, "msn temp");
423 case TYPE_MSN_CHAT:
424 return i18n (2586, "msn chat");
425 case TYPE_MSGLISTEN:
426 return i18n (1947, "listener");
427 case TYPE_MSGDIRECT:
428 return i18n (1890, "peer-to-peer");
429 case TYPE_FILELISTEN:
430 return i18n (2089, "file listener");
431 case TYPE_FILEDIRECT:
432 return i18n (2090, "file peer-to-peer");
433 case TYPE_FILE:
434 return i18n (2067, "file io");
435 case TYPE_XMPPDIRECT:
436 return i18n (2733, "xmpp peer-to-peer");
437 case TYPE_FILEXMPP:
438 return i18n (2734, "xmpp file io");
439 case TYPE_REMOTE:
440 return i18n (2225, "scripting");
441 default:
442 return i18n (1745, "unknown");
443 }
444 }
445
ServerStrType(Server * serv)446 const char *ServerStrType (Server *serv)
447 {
448 switch (serv->type) {
449 case TYPE_XMPP_SERVER:
450 return i18n (2604, "xmpp");
451 case TYPE_MSN_SERVER:
452 return i18n (2735, "msn");
453 case TYPE_SERVER:
454 return i18n (2736, "icq");
455 default:
456 return i18n (1745, "unknown");
457 }
458 }
459
ConnectionServerType(UWORD type)460 const char *ConnectionServerType (UWORD type)
461 {
462 switch (type) {
463 case TYPE_XMPP_SERVER:
464 return "xmpp";
465 case TYPE_MSN_SERVER:
466 return "msn";
467 case TYPE_SERVER:
468 return "icq8";
469 case TYPE_MSGLISTEN:
470 return "peer";
471 case TYPE_REMOTE:
472 return "remote";
473 default:
474 return "unknown";
475 }
476 }
477
ConnectionServerNType(const char * type,char del)478 UWORD ConnectionServerNType (const char *type, char del)
479 {
480 if (!strncmp (type, "icq8", 4) && type[4] == del) return TYPE_SERVER;
481 if (!strncmp (type, "peer", 4) && type[4] == del) return TYPE_MSGLISTEN;
482 if (!strncmp (type, "remote", 6) && type[6] == del) return TYPE_REMOTE;
483 if (!strncmp (type, "msn", 3) && type[3] == del) return TYPE_MSN_SERVER;
484 if (!strncmp (type, "jabber", 6) && type[6] == del) return TYPE_XMPP_SERVER;
485 if (!strncmp (type, "xmpp", 4) && type[4] == del) return TYPE_XMPP_SERVER;
486 return 0;
487 }
488
489
490 /*
491 * Query an option for a contact group
492 */
ServerPrefVal(Server * serv,UDWORD flag)493 val_t ServerPrefVal (Server *serv, UDWORD flag)
494 {
495 val_t res = 0;
496 if (serv->contacts && OptGetVal (&serv->copts, flag, &res))
497 return res;
498 if (OptGetVal (&prG->copts, flag, &res))
499 return res;
500 return 0;
501 }
502
503 /*
504 * Query an option for a contact group
505 */
ServerPrefStr(Server * serv,UDWORD flag)506 const char *ServerPrefStr (Server *serv, UDWORD flag)
507 {
508 const char *res = 0;
509 if (serv->contacts && OptGetStr (&serv->copts, flag, &res))
510 return res;
511 if (OptGetStr (&prG->copts, flag, &res))
512 return res;
513 return 0;
514 }
515
516