source: protocols/msn/sb.c @ 5ebff60

Last change on this file since 5ebff60 was 5ebff60, checked in by dequis <dx@…>, at 2015-02-20T22:50:54Z

Reindent everything to K&R style with tabs

Used uncrustify, with the configuration file in ./doc/uncrustify.cfg

Commit author set to "Indent <please@…>" so that it's easier to
skip while doing git blame.

  • 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                                g_free(m->text);
522                                g_free(m->who);
523                                g_free(m);
524
525                                sb->msgq = g_slist_remove(sb->msgq, m);
526                        }
527
528                        msn_sb_start_keepalives(sb, FALSE);
529
530                        return(st);
531                } else if (strcmp(cmd[1], ic->acc->user) == 0) {
532                        /* Well, gee thanks. Thanks for letting me know I've arrived.. */
533                } else if (sb->who) {
534                        debug("Converting chat with %s to a groupchat because %s joined the session.", sb->who, cmd[1]);
535
536                        /* This SB is a one-to-one chat right now, but someone else is joining. */
537                        msn_sb_to_chat(sb);
538
539                        imcb_chat_add_buddy(sb->chat, cmd[1]);
540                } else if (sb->chat) {
541                        imcb_chat_add_buddy(sb->chat, cmd[1]);
542                        sb->ready = 1;
543                } else {
544                        /* PANIC! */
545                }
546        } else if (strcmp(cmd[0], "MSG") == 0) {
547                if (num_parts < 4) {
548                        msn_sb_destroy(sb);
549                        return(0);
550                }
551
552                sb->handler->msglen = atoi(cmd[3]);
553
554                if (sb->handler->msglen <= 0) {
555                        debug("Received a corrupted message on the switchboard, the switchboard will be closed");
556                        msn_sb_destroy(sb);
557                        return(0);
558                }
559        } else if (strcmp(cmd[0], "NAK") == 0) {
560                if (sb->who) {
561                        imcb_log(ic, "The MSN servers could not deliver one of your messages to %s.", sb->who);
562                } else {
563                        imcb_log(ic,
564                                 "The MSN servers could not deliver one of your groupchat messages to all participants.");
565                }
566        } else if (strcmp(cmd[0], "BYE") == 0) {
567                if (num_parts < 2) {
568                        msn_sb_destroy(sb);
569                        return(0);
570                }
571
572                /* if( cmd[2] && *cmd[2] == '1' ) -=> Chat is being cleaned up because of idleness */
573
574                if (sb->who) {
575                        msn_sb_stop_keepalives(sb);
576
577                        /* This is a single-person chat, and the other person is leaving. */
578                        g_free(sb->who);
579                        sb->who = NULL;
580                        sb->ready = 0;
581
582                        debug("Person %s left the one-to-one switchboard connection. Keeping it around as a spare...",
583                              cmd[1]);
584
585                        /* We could clean up the switchboard now, but keeping it around
586                           as a spare for a next conversation sounds more sane to me.
587                           The server will clean it up when it's idle for too long. */
588                } else if (sb->chat && !strchr(cmd[1], ';')) {
589                        imcb_chat_remove_buddy(sb->chat, cmd[1], "");
590                } else {
591                        /* PANIC! */
592                }
593        } else if (g_ascii_isdigit(cmd[0][0])) {
594                int num = atoi(cmd[0]);
595                const struct msn_status_code *err = msn_status_by_number(num);
596
597                /* If the person is offline, send an offline message instead,
598                   and don't report an error. */
599                if (num == 217) {
600                        msn_ns_oim_send_queue(ic, &sb->msgq);
601                } else {
602                        imcb_error(ic, "Error reported by switchboard server: %s", err->text);
603                }
604
605                if (err->flags & STATUS_SB_FATAL) {
606                        msn_sb_destroy(sb);
607                        return 0;
608                } else if (err->flags & STATUS_FATAL) {
609                        imc_logout(ic, TRUE);
610                        return 0;
611                } else if (err->flags & STATUS_SB_IM_SPARE) {
612                        if (sb->who) {
613                                /* Apparently some invitation failed. We might want to use this
614                                   board later, so keep it as a spare. */
615                                g_free(sb->who);
616                                sb->who = NULL;
617
618                                /* Also clear the msgq, otherwise someone else might get them. */
619                                msn_msgq_purge(ic, &sb->msgq);
620                        }
621
622                        /* Do NOT return 0 here, we want to keep this sb. */
623                }
624        } else {
625                /* debug( "Received unknown command from switchboard server: %s", cmd[0] ); */
626        }
627
628        return(1);
629}
630
631static int msn_sb_message(struct msn_handler_data *handler, char *msg, int msglen, char **cmd, int num_parts)
632{
633        struct msn_switchboard *sb = handler->data;
634        struct im_connection *ic = sb->ic;
635        char *body;
636
637        if (!num_parts) {
638                return(1);
639        }
640
641        if ((body = strstr(msg, "\r\n\r\n"))) {
642                body += 4;
643        }
644
645        if (strcmp(cmd[0], "MSG") == 0) {
646                char *ct = get_rfc822_header(msg, "Content-Type:", msglen);
647
648                if (!ct) {
649                        return(1);
650                }
651
652                if (g_strncasecmp(ct, "text/plain", 10) == 0) {
653                        g_free(ct);
654
655                        if (!body) {
656                                return(1);
657                        }
658
659                        if (sb->who) {
660                                imcb_buddy_msg(ic, cmd[1], body, 0, 0);
661                        } else if (sb->chat) {
662                                imcb_chat_msg(sb->chat, cmd[1], body, 0, 0);
663                        } else {
664                                /* PANIC! */
665                        }
666                }
667#if 0
668                // Disable MSN ft support for now.
669                else if (g_strncasecmp(ct, "text/x-msmsgsinvite", 19) == 0) {
670                        char *command = get_rfc822_header(body, "Invitation-Command:", blen);
671                        char *cookie = get_rfc822_header(body, "Invitation-Cookie:", blen);
672                        unsigned int icookie;
673
674                        g_free(ct);
675
676                        /* Every invite should have both a Command and Cookie header */
677                        if (!command || !cookie) {
678                                g_free(command);
679                                g_free(cookie);
680                                imcb_log(ic, "Warning: No command or cookie from %s", sb->who);
681                                return 1;
682                        }
683
684                        icookie = strtoul(cookie, NULL, 10);
685                        g_free(cookie);
686
687                        if (g_strncasecmp(command, "INVITE", 6) == 0) {
688                                msn_invitation_invite(sb, cmd[1], icookie, body, blen);
689                        } else if (g_strncasecmp(command, "ACCEPT", 6) == 0) {
690                                msn_invitation_accept(sb, cmd[1], icookie, body, blen);
691                        } else if (g_strncasecmp(command, "CANCEL", 6) == 0) {
692                                msn_invitation_cancel(sb, cmd[1], icookie, body, blen);
693                        } else {
694                                imcb_log(ic, "Warning: Received invalid invitation with "
695                                         "command %s from %s", command, sb->who);
696                        }
697
698                        g_free(command);
699                }
700#endif
701                else if (g_strncasecmp(ct, "application/x-msnmsgrp2p", 24) == 0) {
702                        /* Not currently implemented. Don't warn about it since
703                           this seems to be used for avatars now. */
704                        g_free(ct);
705                } else if (g_strncasecmp(ct, "text/x-msmsgscontrol", 20) == 0) {
706                        char *who = get_rfc822_header(msg, "TypingUser:", msglen);
707
708                        if (who) {
709                                imcb_buddy_typing(ic, who, OPT_TYPING);
710                                g_free(who);
711                        }
712
713                        g_free(ct);
714                } else {
715                        g_free(ct);
716                }
717        }
718
719        return(1);
720}
721
722static gboolean msn_sb_keepalive(gpointer data, gint source, b_input_condition cond)
723{
724        struct msn_switchboard *sb = data;
725
726        return sb->ready && msn_sb_sendmessage(sb, SB_KEEPALIVE_MESSAGE);
727}
728
729void msn_sb_start_keepalives(struct msn_switchboard *sb, gboolean initial)
730{
731        bee_user_t *bu;
732
733        if (sb && sb->who && sb->keepalive == 0 &&
734            (bu = bee_user_by_handle(sb->ic->bee, sb->ic, sb->who)) &&
735            !(bu->flags & BEE_USER_ONLINE) &&
736            set_getbool(&sb->ic->acc->set, "switchboard_keepalives")) {
737                if (initial) {
738                        msn_sb_keepalive(sb, 0, 0);
739                }
740
741                sb->keepalive = b_timeout_add(20000, msn_sb_keepalive, sb);
742        }
743}
744
745void msn_sb_stop_keepalives(struct msn_switchboard *sb)
746{
747        if (sb && sb->keepalive > 0) {
748                b_event_remove(sb->keepalive);
749                sb->keepalive = 0;
750        }
751}
Note: See TracBrowser for help on using the repository browser.