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

Last change on this file since 5d1b3a95 was ec86b22, checked in by Wilmer van der Gaast <wilmer@…>, at 2010-05-15T23:28:16Z

Mainline merge. (Probably mostly irrelevant for this branch, oh well.)

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