source: protocols/msn/sb.c @ 1522faf

Last change on this file since 1522faf was 05816dd, checked in by dequis <dx@…>, at 2015-02-22T22:44:40Z

coverity: Fix some (harmless?) use-after-free with g_slist_remove()

These were passing a pointer to a variable right after it was g_free()'d

They are most likely harmless as g_slist_remove() probably just needs
the pointer location, but fixing it anyway.

  • Property mode set to 100644
File size: 18.9 KB
Line 
1/********************************************************************\
2  * BitlBee -- An IRC to other IM-networks gateway                     *
3  *                                                                    *
4  * Copyright 2002-2012 Wilmer van der Gaast and others                *
5  \********************************************************************/
6
7/* MSN module - Switchboard server callbacks and utilities              */
8
9/*
10  This program is free software; you can redistribute it and/or modify
11  it under the terms of the GNU General Public License as published by
12  the Free Software Foundation; either version 2 of the License, or
13  (at your option) any later version.
14
15  This program is distributed in the hope that it will be useful,
16  but WITHOUT ANY WARRANTY; without even the implied warranty of
17  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  GNU General Public License for more details.
19
20  You should have received a copy of the GNU General Public License with
21  the Debian GNU/Linux distribution in /usr/share/common-licenses/GPL;
22  if not, write to the Free Software Foundation, Inc., 51 Franklin St.,
23  Fifth Floor, Boston, MA  02110-1301  USA
24*/
25
26#include <ctype.h>
27#include "nogaim.h"
28#include "msn.h"
29#include "md5.h"
30#include "soap.h"
31#include "invitation.h"
32
33static gboolean msn_sb_callback(gpointer data, gint source, b_input_condition cond);
34static int msn_sb_command(struct msn_handler_data *handler, char **cmd, int num_parts);
35static int msn_sb_message(struct msn_handler_data *handler, char *msg, int msglen, char **cmd, int num_parts);
36
37int msn_sb_write(struct msn_switchboard *sb, const char *fmt, ...)
38{
39        va_list params;
40        char *out;
41        size_t len;
42        int st;
43
44        va_start(params, fmt);
45        out = g_strdup_vprintf(fmt, params);
46        va_end(params);
47
48        if (getenv("BITLBEE_DEBUG")) {
49                fprintf(stderr, "->SB%d:%s\n", sb->fd, out);
50        }
51
52        len = strlen(out);
53        st = write(sb->fd, out, len);
54        g_free(out);
55        if (st != len) {
56                msn_sb_destroy(sb);
57                return 0;
58        }
59
60        return 1;
61}
62
63int msn_sb_write_msg(struct im_connection *ic, struct msn_message *m)
64{
65        struct msn_data *md = ic->proto_data;
66        struct msn_switchboard *sb;
67
68        /* FIXME: *CHECK* the reliability of using spare sb's! */
69        if ((sb = msn_sb_spare(ic))) {
70                debug("Trying to use a spare switchboard to message %s", m->who);
71
72                sb->who = g_strdup(m->who);
73                if (msn_sb_write(sb, "CAL %d %s\r\n", ++sb->trId, m->who)) {
74                        /* He/She should join the switchboard soon, let's queue the message. */
75                        sb->msgq = g_slist_append(sb->msgq, m);
76                        return(1);
77                }
78        }
79
80        debug("Creating a new switchboard to message %s", m->who);
81
82        /* If we reach this line, there was no spare switchboard, so let's make one. */
83        if (!msn_ns_write(ic, -1, "XFR %d SB\r\n", ++md->trId)) {
84                g_free(m->who);
85                g_free(m->text);
86                g_free(m);
87
88                return(0);
89        }
90
91        /* And queue the message to md. We'll pick it up when the switchboard comes up. */
92        md->msgq = g_slist_append(md->msgq, m);
93
94        /* FIXME: If the switchboard creation fails, the message will not be sent. */
95
96        return(1);
97}
98
99struct msn_switchboard *msn_sb_create(struct im_connection *ic, char *host, int port, char *key, int session)
100{
101        struct msn_data *md = ic->proto_data;
102        struct msn_switchboard *sb = g_new0(struct msn_switchboard, 1);
103
104        sb->fd = proxy_connect(host, port, msn_sb_connected, sb);
105        if (sb->fd < 0) {
106                g_free(sb);
107                return(NULL);
108        }
109
110        sb->ic = ic;
111        sb->key = g_strdup(key);
112        sb->session = session;
113
114        msn_switchboards = g_slist_append(msn_switchboards, sb);
115        md->switchboards = g_slist_append(md->switchboards, sb);
116
117        return(sb);
118}
119
120struct msn_switchboard *msn_sb_by_handle(struct im_connection *ic, const char *handle)
121{
122        struct msn_data *md = ic->proto_data;
123        struct msn_switchboard *sb;
124        GSList *l;
125
126        for (l = md->switchboards; l; l = l->next) {
127                sb = l->data;
128                if (sb->who && strcmp(sb->who, handle) == 0) {
129                        return(sb);
130                }
131        }
132
133        return(NULL);
134}
135
136struct msn_switchboard *msn_sb_by_chat(struct groupchat *c)
137{
138        struct msn_data *md = c->ic->proto_data;
139        struct msn_switchboard *sb;
140        GSList *l;
141
142        for (l = md->switchboards; l; l = l->next) {
143                sb = l->data;
144                if (sb->chat == c) {
145                        return(sb);
146                }
147        }
148
149        return(NULL);
150}
151
152struct msn_switchboard *msn_sb_spare(struct im_connection *ic)
153{
154        struct msn_data *md = ic->proto_data;
155        struct msn_switchboard *sb;
156        GSList *l;
157
158        for (l = md->switchboards; l; l = l->next) {
159                sb = l->data;
160                if (!sb->who && !sb->chat) {
161                        return(sb);
162                }
163        }
164
165        return(NULL);
166}
167
168int msn_sb_sendmessage(struct msn_switchboard *sb, char *text)
169{
170        if (sb->ready) {
171                char *buf;
172                int i, j;
173
174                /* Build the message. Convert LF to CR-LF for normal messages. */
175                if (strcmp(text, TYPING_NOTIFICATION_MESSAGE) == 0) {
176                        i = strlen(MSN_TYPING_HEADERS) + strlen(sb->ic->acc->user);
177                        buf = g_new0(char, i);
178                        i = g_snprintf(buf, i, MSN_TYPING_HEADERS, sb->ic->acc->user);
179                } else if (strcmp(text, NUDGE_MESSAGE) == 0) {
180                        buf = g_strdup(MSN_NUDGE_HEADERS);
181                        i = strlen(buf);
182                } else if (strcmp(text, SB_KEEPALIVE_MESSAGE) == 0) {
183                        buf = g_strdup(MSN_SB_KEEPALIVE_HEADERS);
184                        i = strlen(buf);
185                } else if (strncmp(text, MSN_INVITE_HEADERS, sizeof(MSN_INVITE_HEADERS) - 1) == 0) {
186                        buf = g_strdup(text);
187                        i = strlen(buf);
188                } else {
189                        buf = g_new0(char, sizeof(MSN_MESSAGE_HEADERS) + strlen(text) * 2 + 1);
190                        i = strlen(MSN_MESSAGE_HEADERS);
191
192                        strcpy(buf, MSN_MESSAGE_HEADERS);
193                        for (j = 0; text[j]; j++) {
194                                if (text[j] == '\n') {
195                                        buf[i++] = '\r';
196                                }
197
198                                buf[i++] = text[j];
199                        }
200                }
201
202                /* Build the final packet (MSG command + the message). */
203                if (msn_sb_write(sb, "MSG %d N %d\r\n%s", ++sb->trId, i, buf)) {
204                        g_free(buf);
205                        return 1;
206                } else {
207                        g_free(buf);
208                        return 0;
209                }
210        } else if (sb->who) {
211                struct msn_message *m = g_new0(struct msn_message, 1);
212
213                m->who = g_strdup("");
214                m->text = g_strdup(text);
215                sb->msgq = g_slist_append(sb->msgq, m);
216
217                return(1);
218        } else {
219                return(0);
220        }
221}
222
223struct groupchat *msn_sb_to_chat(struct msn_switchboard *sb)
224{
225        struct im_connection *ic = sb->ic;
226        struct groupchat *c = NULL;
227        char buf[1024];
228
229        /* Create the groupchat structure. */
230        g_snprintf(buf, sizeof(buf), "MSN groupchat session %d", sb->session);
231        if (sb->who) {
232                c = bee_chat_by_title(ic->bee, ic, sb->who);
233        }
234        if (c && !msn_sb_by_chat(c)) {
235                sb->chat = c;
236        } else {
237                sb->chat = imcb_chat_new(ic, buf);
238        }
239
240        /* Populate the channel. */
241        if (sb->who) {
242                imcb_chat_add_buddy(sb->chat, sb->who);
243        }
244        imcb_chat_add_buddy(sb->chat, ic->acc->user);
245
246        /* And make sure the switchboard doesn't look like a regular chat anymore. */
247        if (sb->who) {
248                g_free(sb->who);
249                sb->who = NULL;
250        }
251
252        return sb->chat;
253}
254
255void msn_sb_destroy(struct msn_switchboard *sb)
256{
257        struct im_connection *ic = sb->ic;
258        struct msn_data *md = ic->proto_data;
259
260        debug("Destroying switchboard: %s", sb->who ? sb->who : sb->key ? sb->key : "");
261
262        msn_msgq_purge(ic, &sb->msgq);
263        msn_sb_stop_keepalives(sb);
264
265        if (sb->key) {
266                g_free(sb->key);
267        }
268        if (sb->who) {
269                g_free(sb->who);
270        }
271
272        if (sb->chat) {
273                imcb_chat_free(sb->chat);
274        }
275
276        if (sb->handler) {
277                if (sb->handler->rxq) {
278                        g_free(sb->handler->rxq);
279                }
280                if (sb->handler->cmd_text) {
281                        g_free(sb->handler->cmd_text);
282                }
283                g_free(sb->handler);
284        }
285
286        if (sb->inp) {
287                b_event_remove(sb->inp);
288        }
289        closesocket(sb->fd);
290
291        msn_switchboards = g_slist_remove(msn_switchboards, sb);
292        md->switchboards = g_slist_remove(md->switchboards, sb);
293        g_free(sb);
294}
295
296gboolean msn_sb_connected(gpointer data, gint source, b_input_condition cond)
297{
298        struct msn_switchboard *sb = data;
299        struct im_connection *ic;
300        struct msn_data *md;
301        char buf[1024];
302
303        /* Are we still alive? */
304        if (!g_slist_find(msn_switchboards, sb)) {
305                return FALSE;
306        }
307
308        ic = sb->ic;
309        md = ic->proto_data;
310
311        if (source != sb->fd) {
312                debug("Error %d while connecting to switchboard server", 1);
313                msn_sb_destroy(sb);
314                return FALSE;
315        }
316
317        /* Prepare the callback */
318        sb->handler = g_new0(struct msn_handler_data, 1);
319        sb->handler->fd = sb->fd;
320        sb->handler->rxq = g_new0(char, 1);
321        sb->handler->data = sb;
322        sb->handler->exec_command = msn_sb_command;
323        sb->handler->exec_message = msn_sb_message;
324
325        if (sb->session == MSN_SB_NEW) {
326                g_snprintf(buf, sizeof(buf), "USR %d %s;{%s} %s\r\n", ++sb->trId, ic->acc->user, md->uuid, sb->key);
327        } else {
328                g_snprintf(buf, sizeof(buf), "ANS %d %s;{%s} %s %d\r\n", ++sb->trId, ic->acc->user, md->uuid, sb->key,
329                           sb->session);
330        }
331
332        if (msn_sb_write(sb, "%s", buf)) {
333                sb->inp = b_input_add(sb->fd, B_EV_IO_READ, msn_sb_callback, sb);
334        } else {
335                debug("Error %d while connecting to switchboard server", 2);
336        }
337
338        return FALSE;
339}
340
341static gboolean msn_sb_callback(gpointer data, gint source, b_input_condition cond)
342{
343        struct msn_switchboard *sb = data;
344        struct im_connection *ic = sb->ic;
345        struct msn_data *md = ic->proto_data;
346
347        if (msn_handler(sb->handler) != -1) {
348                return TRUE;
349        }
350
351        if (sb->msgq != NULL) {
352                time_t now = time(NULL);
353
354                if (now - md->first_sb_failure > 600) {
355                        /* It's not really the first one, but the start of this "series".
356                           With this, the warning below will be shown only if this happens
357                           at least three times in ten minutes. This algorithm isn't
358                           perfect, but for this purpose it will do. */
359                        md->first_sb_failure = now;
360                        md->sb_failures = 0;
361                }
362
363                debug("Error: Switchboard died");
364                if (++md->sb_failures >= 3) {
365                        imcb_log(ic, "Warning: Many switchboard failures on MSN connection. "
366                                 "There might be problems delivering your messages.");
367                }
368
369                if (md->msgq == NULL) {
370                        md->msgq = sb->msgq;
371                } else {
372                        GSList *l;
373
374                        for (l = md->msgq; l->next; l = l->next) {
375                                ;
376                        }
377                        l->next = sb->msgq;
378                }
379                sb->msgq = NULL;
380
381                debug("Moved queued messages back to the main queue, "
382                      "creating a new switchboard to retry.");
383                if (!msn_ns_write(ic, -1, "XFR %d SB\r\n", ++md->trId)) {
384                        return FALSE;
385                }
386        }
387
388        msn_sb_destroy(sb);
389        return FALSE;
390}
391
392static int msn_sb_command(struct msn_handler_data *handler, char **cmd, int num_parts)
393{
394        struct msn_switchboard *sb = handler->data;
395        struct im_connection *ic = sb->ic;
396
397        if (!num_parts) {
398                /* Hrrm... Empty command...? Ignore? */
399                return(1);
400        }
401
402        if (strcmp(cmd[0], "XFR") == 0) {
403                imcb_error(ic,
404                           "Received an XFR from a switchboard server, unable to comply! This is likely to be a bug, please report it!");
405                imc_logout(ic, TRUE);
406                return(0);
407        } else if (strcmp(cmd[0], "USR") == 0) {
408                if (num_parts < 5) {
409                        msn_sb_destroy(sb);
410                        return(0);
411                }
412
413                if (strcmp(cmd[2], "OK") != 0) {
414                        msn_sb_destroy(sb);
415                        return(0);
416                }
417
418                if (sb->who) {
419                        return msn_sb_write(sb, "CAL %d %s\r\n", ++sb->trId, sb->who);
420                } else {
421                        debug("Just created a switchboard, but I don't know what to do with it.");
422                }
423        } else if (strcmp(cmd[0], "IRO") == 0) {
424                int num, tot;
425
426                if (num_parts < 6) {
427                        msn_sb_destroy(sb);
428                        return(0);
429                }
430
431                num = atoi(cmd[2]);
432                tot = atoi(cmd[3]);
433
434                if (tot <= 0) {
435                        msn_sb_destroy(sb);
436                        return(0);
437                } else if (tot > 1) {
438                        char buf[1024];
439
440                        /* For as much as I understand this MPOP stuff now, a
441                           switchboard has two (or more) roster entries per
442                           participant. One "bare JID" and one JID;UUID. Ignore
443                           the latter. */
444                        if (!strchr(cmd[4], ';')) {
445                                /* HACK: Since even 1:1 chats now have >2 participants
446                                   (ourselves included) it gets hard to tell them apart
447                                   from rooms. Let's hope this is enough: */
448                                if (sb->chat == NULL && num != tot) {
449                                        g_snprintf(buf, sizeof(buf), "MSN groupchat session %d", sb->session);
450                                        sb->chat = imcb_chat_new(ic, buf);
451
452                                        g_free(sb->who);
453                                        sb->who = NULL;
454                                }
455
456                                if (sb->chat) {
457                                        imcb_chat_add_buddy(sb->chat, cmd[4]);
458                                }
459                        }
460
461                        /* We have the full roster, start showing the channel to
462                           the user. */
463                        if (num == tot && sb->chat) {
464                                imcb_chat_add_buddy(sb->chat, ic->acc->user);
465                        }
466                }
467        } else if (strcmp(cmd[0], "ANS") == 0) {
468                if (num_parts < 3) {
469                        msn_sb_destroy(sb);
470                        return(0);
471                }
472
473                if (strcmp(cmd[2], "OK") != 0) {
474                        debug("Switchboard server sent a negative ANS reply");
475                        msn_sb_destroy(sb);
476                        return(0);
477                }
478
479                sb->ready = 1;
480
481                msn_sb_start_keepalives(sb, FALSE);
482        } else if (strcmp(cmd[0], "CAL") == 0) {
483                if (num_parts < 4 || !g_ascii_isdigit(cmd[3][0])) {
484                        msn_sb_destroy(sb);
485                        return(0);
486                }
487
488                sb->session = atoi(cmd[3]);
489        } else if (strcmp(cmd[0], "JOI") == 0) {
490                if (num_parts < 3) {
491                        msn_sb_destroy(sb);
492                        return(0);
493                }
494
495                /* See IRO above. Handle "bare JIDs" only. */
496                if (strchr(cmd[1], ';')) {
497                        return 1;
498                }
499
500                if (sb->who && g_strcasecmp(cmd[1], sb->who) == 0) {
501                        /* The user we wanted to talk to is finally there, let's send the queued messages then. */
502                        struct msn_message *m;
503                        GSList *l;
504                        int st = 1;
505
506                        debug("%s arrived in the switchboard session, now sending queued message(s)", cmd[1]);
507
508                        /* Without this, sendmessage() will put everything back on the queue... */
509                        sb->ready = 1;
510
511                        while ((l = sb->msgq)) {
512                                m = l->data;
513                                if (st) {
514                                        /* This hack is meant to convert a regular new chat into a groupchat */
515                                        if (strcmp(m->text, GROUPCHAT_SWITCHBOARD_MESSAGE) == 0) {
516                                                msn_sb_to_chat(sb);
517                                        } else {
518                                                st = msn_sb_sendmessage(sb, m->text);
519                                        }
520                                }
521                                sb->msgq = g_slist_remove(sb->msgq, m);
522                                g_free(m->text);
523                                g_free(m->who);
524                                g_free(m);
525                        }
526
527                        msn_sb_start_keepalives(sb, FALSE);
528
529                        return(st);
530                } else if (strcmp(cmd[1], ic->acc->user) == 0) {
531                        /* Well, gee thanks. Thanks for letting me know I've arrived.. */
532                } else if (sb->who) {
533                        debug("Converting chat with %s to a groupchat because %s joined the session.", sb->who, cmd[1]);
534
535                        /* This SB is a one-to-one chat right now, but someone else is joining. */
536                        msn_sb_to_chat(sb);
537
538                        imcb_chat_add_buddy(sb->chat, cmd[1]);
539                } else if (sb->chat) {
540                        imcb_chat_add_buddy(sb->chat, cmd[1]);
541                        sb->ready = 1;
542                } else {
543                        /* PANIC! */
544                }
545        } else if (strcmp(cmd[0], "MSG") == 0) {
546                if (num_parts < 4) {
547                        msn_sb_destroy(sb);
548                        return(0);
549                }
550
551                sb->handler->msglen = atoi(cmd[3]);
552
553                if (sb->handler->msglen <= 0) {
554                        debug("Received a corrupted message on the switchboard, the switchboard will be closed");
555                        msn_sb_destroy(sb);
556                        return(0);
557                }
558        } else if (strcmp(cmd[0], "NAK") == 0) {
559                if (sb->who) {
560                        imcb_log(ic, "The MSN servers could not deliver one of your messages to %s.", sb->who);
561                } else {
562                        imcb_log(ic,
563                                 "The MSN servers could not deliver one of your groupchat messages to all participants.");
564                }
565        } else if (strcmp(cmd[0], "BYE") == 0) {
566                if (num_parts < 2) {
567                        msn_sb_destroy(sb);
568                        return(0);
569                }
570
571                /* if( cmd[2] && *cmd[2] == '1' ) -=> Chat is being cleaned up because of idleness */
572
573                if (sb->who) {
574                        msn_sb_stop_keepalives(sb);
575
576                        /* This is a single-person chat, and the other person is leaving. */
577                        g_free(sb->who);
578                        sb->who = NULL;
579                        sb->ready = 0;
580
581                        debug("Person %s left the one-to-one switchboard connection. Keeping it around as a spare...",
582                              cmd[1]);
583
584                        /* We could clean up the switchboard now, but keeping it around
585                           as a spare for a next conversation sounds more sane to me.
586                           The server will clean it up when it's idle for too long. */
587                } else if (sb->chat && !strchr(cmd[1], ';')) {
588                        imcb_chat_remove_buddy(sb->chat, cmd[1], "");
589                } else {
590                        /* PANIC! */
591                }
592        } else if (g_ascii_isdigit(cmd[0][0])) {
593                int num = atoi(cmd[0]);
594                const struct msn_status_code *err = msn_status_by_number(num);
595
596                /* If the person is offline, send an offline message instead,
597                   and don't report an error. */
598                if (num == 217) {
599                        msn_ns_oim_send_queue(ic, &sb->msgq);
600                } else {
601                        imcb_error(ic, "Error reported by switchboard server: %s", err->text);
602                }
603
604                if (err->flags & STATUS_SB_FATAL) {
605                        msn_sb_destroy(sb);
606                        return 0;
607                } else if (err->flags & STATUS_FATAL) {
608                        imc_logout(ic, TRUE);
609                        return 0;
610                } else if (err->flags & STATUS_SB_IM_SPARE) {
611                        if (sb->who) {
612                                /* Apparently some invitation failed. We might want to use this
613                                   board later, so keep it as a spare. */
614                                g_free(sb->who);
615                                sb->who = NULL;
616
617                                /* Also clear the msgq, otherwise someone else might get them. */
618                                msn_msgq_purge(ic, &sb->msgq);
619                        }
620
621                        /* Do NOT return 0 here, we want to keep this sb. */
622                }
623        } else {
624                /* debug( "Received unknown command from switchboard server: %s", cmd[0] ); */
625        }
626
627        return(1);
628}
629
630static int msn_sb_message(struct msn_handler_data *handler, char *msg, int msglen, char **cmd, int num_parts)
631{
632        struct msn_switchboard *sb = handler->data;
633        struct im_connection *ic = sb->ic;
634        char *body;
635
636        if (!num_parts) {
637                return(1);
638        }
639
640        if ((body = strstr(msg, "\r\n\r\n"))) {
641                body += 4;
642        }
643
644        if (strcmp(cmd[0], "MSG") == 0) {
645                char *ct = get_rfc822_header(msg, "Content-Type:", msglen);
646
647                if (!ct) {
648                        return(1);
649                }
650
651                if (g_strncasecmp(ct, "text/plain", 10) == 0) {
652                        g_free(ct);
653
654                        if (!body) {
655                                return(1);
656                        }
657
658                        if (sb->who) {
659                                imcb_buddy_msg(ic, cmd[1], body, 0, 0);
660                        } else if (sb->chat) {
661                                imcb_chat_msg(sb->chat, cmd[1], body, 0, 0);
662                        } else {
663                                /* PANIC! */
664                        }
665                }
666#if 0
667                // Disable MSN ft support for now.
668                else if (g_strncasecmp(ct, "text/x-msmsgsinvite", 19) == 0) {
669                        char *command = get_rfc822_header(body, "Invitation-Command:", blen);
670                        char *cookie = get_rfc822_header(body, "Invitation-Cookie:", blen);
671                        unsigned int icookie;
672
673                        g_free(ct);
674
675                        /* Every invite should have both a Command and Cookie header */
676                        if (!command || !cookie) {
677                                g_free(command);
678                                g_free(cookie);
679                                imcb_log(ic, "Warning: No command or cookie from %s", sb->who);
680                                return 1;
681                        }
682
683                        icookie = strtoul(cookie, NULL, 10);
684                        g_free(cookie);
685
686                        if (g_strncasecmp(command, "INVITE", 6) == 0) {
687                                msn_invitation_invite(sb, cmd[1], icookie, body, blen);
688                        } else if (g_strncasecmp(command, "ACCEPT", 6) == 0) {
689                                msn_invitation_accept(sb, cmd[1], icookie, body, blen);
690                        } else if (g_strncasecmp(command, "CANCEL", 6) == 0) {
691                                msn_invitation_cancel(sb, cmd[1], icookie, body, blen);
692                        } else {
693                                imcb_log(ic, "Warning: Received invalid invitation with "
694                                         "command %s from %s", command, sb->who);
695                        }
696
697                        g_free(command);
698                }
699#endif
700                else if (g_strncasecmp(ct, "application/x-msnmsgrp2p", 24) == 0) {
701                        /* Not currently implemented. Don't warn about it since
702                           this seems to be used for avatars now. */
703                        g_free(ct);
704                } else if (g_strncasecmp(ct, "text/x-msmsgscontrol", 20) == 0) {
705                        char *who = get_rfc822_header(msg, "TypingUser:", msglen);
706
707                        if (who) {
708                                imcb_buddy_typing(ic, who, OPT_TYPING);
709                                g_free(who);
710                        }
711
712                        g_free(ct);
713                } else {
714                        g_free(ct);
715                }
716        }
717
718        return(1);
719}
720
721static gboolean msn_sb_keepalive(gpointer data, gint source, b_input_condition cond)
722{
723        struct msn_switchboard *sb = data;
724
725        return sb->ready && msn_sb_sendmessage(sb, SB_KEEPALIVE_MESSAGE);
726}
727
728void msn_sb_start_keepalives(struct msn_switchboard *sb, gboolean initial)
729{
730        bee_user_t *bu;
731
732        if (sb && sb->who && sb->keepalive == 0 &&
733            (bu = bee_user_by_handle(sb->ic->bee, sb->ic, sb->who)) &&
734            !(bu->flags & BEE_USER_ONLINE) &&
735            set_getbool(&sb->ic->acc->set, "switchboard_keepalives")) {
736                if (initial) {
737                        msn_sb_keepalive(sb, 0, 0);
738                }
739
740                sb->keepalive = b_timeout_add(20000, msn_sb_keepalive, sb);
741        }
742}
743
744void msn_sb_stop_keepalives(struct msn_switchboard *sb)
745{
746        if (sb && sb->keepalive > 0) {
747                b_event_remove(sb->keepalive);
748                sb->keepalive = 0;
749        }
750}
Note: See TracBrowser for help on using the repository browser.