source: protocols/msn/sb.c @ ae3dc99

Last change on this file since ae3dc99 was ae3dc99, checked in by Wilmer van der Gaast <wilmer@…>, at 2010-04-24T17:02:07Z

Merging stuff from mainline (1.2.6).

  • 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        {
338                time_t now = time( NULL );
339               
340                if( now - md->first_sb_failure > 600 )
341                {
342                        /* It's not really the first one, but the start of this "series".
343                           With this, the warning below will be shown only if this happens
344                           at least three times in ten minutes. This algorithm isn't
345                           perfect, but for this purpose it will do. */
346                        md->first_sb_failure = now;
347                        md->sb_failures = 0;
348                }
349               
350                debug( "Error: Switchboard died" );
351                if( ++ md->sb_failures >= 3 )
352                        imcb_log( ic, "Warning: Many switchboard failures on MSN connection. "
353                                      "There might be problems delivering your messages." );
354               
355                if( sb->msgq != NULL )
356                {
357                        char buf[1024];
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, creating a new switchboard to retry." );
373                        g_snprintf( buf, sizeof( buf ), "XFR %d SB\r\n", ++md->trId );
374                        if( !msn_write( ic, buf, strlen( buf ) ) )
375                                return FALSE;
376                }
377               
378                msn_sb_destroy( sb );
379               
380                return FALSE;
381        }
382        else
383        {
384                return TRUE;
385        }
386}
387
388static int msn_sb_command( gpointer data, char **cmd, int num_parts )
389{
390        struct msn_switchboard *sb = data;
391        struct im_connection *ic = sb->ic;
392        char buf[1024];
393       
394        if( !num_parts )
395        {
396                /* Hrrm... Empty command...? Ignore? */
397                return( 1 );
398        }
399       
400        if( strcmp( cmd[0], "XFR" ) == 0 )
401        {
402                imcb_error( ic, "Received an XFR from a switchboard server, unable to comply! This is likely to be a bug, please report it!" );
403                imc_logout( ic, TRUE );
404                return( 0 );
405        }
406        else if( strcmp( cmd[0], "USR" ) == 0 )
407        {
408                if( num_parts != 5 )
409                {
410                        msn_sb_destroy( sb );
411                        return( 0 );
412                }
413               
414                if( strcmp( cmd[2], "OK" ) != 0 )
415                {
416                        msn_sb_destroy( sb );
417                        return( 0 );
418                }
419               
420                if( sb->who )
421                {
422                        g_snprintf( buf, sizeof( buf ), "CAL %d %s\r\n", ++sb->trId, sb->who );
423                        return( msn_sb_write( sb, buf, strlen( buf ) ) );
424                }
425                else
426                {
427                        debug( "Just created a switchboard, but I don't know what to do with it." );
428                }
429        }
430        else if( strcmp( cmd[0], "IRO" ) == 0 )
431        {
432                int num, tot;
433               
434                if( num_parts != 6 )
435                {
436                        msn_sb_destroy( sb );
437                        return( 0 );
438                }
439               
440                num = atoi( cmd[2] );
441                tot = atoi( cmd[3] );
442               
443                if( tot <= 0 )
444                {
445                        msn_sb_destroy( sb );
446                        return( 0 );
447                }
448                else if( tot > 1 )
449                {
450                        char buf[1024];
451                       
452                        if( num == 1 )
453                        {
454                                g_snprintf( buf, sizeof( buf ), "MSN groupchat session %d", sb->session );
455                                sb->chat = imcb_chat_new( ic, buf );
456                               
457                                g_free( sb->who );
458                                sb->who = NULL;
459                        }
460                       
461                        imcb_chat_add_buddy( sb->chat, cmd[4] );
462                       
463                        if( num == tot )
464                        {
465                                imcb_chat_add_buddy( sb->chat, ic->acc->user );
466                        }
467                }
468        }
469        else if( strcmp( cmd[0], "ANS" ) == 0 )
470        {
471                if( num_parts != 3 )
472                {
473                        msn_sb_destroy( sb );
474                        return( 0 );
475                }
476               
477                if( strcmp( cmd[2], "OK" ) != 0 )
478                {
479                        debug( "Switchboard server sent a negative ANS reply" );
480                        msn_sb_destroy( sb );
481                        return( 0 );
482                }
483               
484                sb->ready = 1;
485               
486                msn_sb_start_keepalives( sb, FALSE );
487        }
488        else if( strcmp( cmd[0], "CAL" ) == 0 )
489        {
490                if( num_parts != 4 || !isdigit( cmd[3][0] ) )
491                {
492                        msn_sb_destroy( sb );
493                        return( 0 );
494                }
495               
496                sb->session = atoi( cmd[3] );
497        }
498        else if( strcmp( cmd[0], "JOI" ) == 0 )
499        {
500                if( num_parts != 3 )
501                {
502                        msn_sb_destroy( sb );
503                        return( 0 );
504                }
505               
506                if( sb->who && g_strcasecmp( cmd[1], sb->who ) == 0 )
507                {
508                        /* The user we wanted to talk to is finally there, let's send the queued messages then. */
509                        struct msn_message *m;
510                        GSList *l;
511                        int st = 1;
512                       
513                        debug( "%s arrived in the switchboard session, now sending queued message(s)", cmd[1] );
514                       
515                        /* Without this, sendmessage() will put everything back on the queue... */
516                        sb->ready = 1;
517                       
518                        while( ( l = sb->msgq ) )
519                        {
520                                m = l->data;
521                                if( st )
522                                {
523                                        /* This hack is meant to convert a regular new chat into a groupchat */
524                                        if( strcmp( m->text, GROUPCHAT_SWITCHBOARD_MESSAGE ) == 0 )
525                                                msn_sb_to_chat( sb );
526                                        else
527                                                st = msn_sb_sendmessage( sb, m->text );
528                                }
529                                g_free( m->text );
530                                g_free( m->who );
531                                g_free( m );
532                               
533                                sb->msgq = g_slist_remove( sb->msgq, m );
534                        }
535                       
536                        msn_sb_start_keepalives( sb, FALSE );
537                       
538                        return( st );
539                }
540                else if( sb->who )
541                {
542                        debug( "Converting chat with %s to a groupchat because %s joined the session.", sb->who, cmd[1] );
543                       
544                        /* This SB is a one-to-one chat right now, but someone else is joining. */
545                        msn_sb_to_chat( sb );
546                       
547                        imcb_chat_add_buddy( sb->chat, cmd[1] );
548                }
549                else if( sb->chat )
550                {
551                        imcb_chat_add_buddy( sb->chat, cmd[1] );
552                        sb->ready = 1;
553                }
554                else
555                {
556                        /* PANIC! */
557                }
558        }
559        else if( strcmp( cmd[0], "MSG" ) == 0 )
560        {
561                if( num_parts != 4 )
562                {
563                        msn_sb_destroy( sb );
564                        return( 0 );
565                }
566               
567                sb->handler->msglen = atoi( cmd[3] );
568               
569                if( sb->handler->msglen <= 0 )
570                {
571                        debug( "Received a corrupted message on the switchboard, the switchboard will be closed" );
572                        msn_sb_destroy( sb );
573                        return( 0 );
574                }
575        }
576        else if( strcmp( cmd[0], "NAK" ) == 0 )
577        {
578                if( sb->who )
579                {
580                        imcb_log( ic, "The MSN servers could not deliver one of your messages to %s.", sb->who );
581                }
582                else
583                {
584                        imcb_log( ic, "The MSN servers could not deliver one of your groupchat messages to all participants." );
585                }
586        }
587        else if( strcmp( cmd[0], "BYE" ) == 0 )
588        {
589                if( num_parts < 2 )
590                {
591                        msn_sb_destroy( sb );
592                        return( 0 );
593                }
594               
595                /* if( cmd[2] && *cmd[2] == '1' ) -=> Chat is being cleaned up because of idleness */
596               
597                if( sb->who )
598                {
599                        msn_sb_stop_keepalives( sb );
600                       
601                        /* This is a single-person chat, and the other person is leaving. */
602                        g_free( sb->who );
603                        sb->who = NULL;
604                        sb->ready = 0;
605                       
606                        debug( "Person %s left the one-to-one switchboard connection. Keeping it around as a spare...", cmd[1] );
607                       
608                        /* We could clean up the switchboard now, but keeping it around
609                           as a spare for a next conversation sounds more sane to me.
610                           The server will clean it up when it's idle for too long. */
611                }
612                else if( sb->chat )
613                {
614                        imcb_chat_remove_buddy( sb->chat, cmd[1], "" );
615                }
616                else
617                {
618                        /* PANIC! */
619                }
620        }
621        else if( isdigit( cmd[0][0] ) )
622        {
623                int num = atoi( cmd[0] );
624                const struct msn_status_code *err = msn_status_by_number( num );
625               
626                imcb_error( ic, "Error reported by switchboard server: %s", err->text );
627               
628                if( err->flags & STATUS_SB_FATAL )
629                {
630                        msn_sb_destroy( sb );
631                        return 0;
632                }
633                else if( err->flags & STATUS_FATAL )
634                {
635                        imc_logout( ic, TRUE );
636                        return 0;
637                }
638                else if( err->flags & STATUS_SB_IM_SPARE )
639                {
640                        if( sb->who )
641                        {
642                                /* Apparently some invitation failed. We might want to use this
643                                   board later, so keep it as a spare. */
644                                g_free( sb->who );
645                                sb->who = NULL;
646                               
647                                /* Also clear the msgq, otherwise someone else might get them. */
648                                msn_msgq_purge( ic, &sb->msgq );
649                        }
650                       
651                        /* Do NOT return 0 here, we want to keep this sb. */
652                }
653        }
654        else
655        {
656                /* debug( "Received unknown command from switchboard server: %s", cmd[0] ); */
657        }
658       
659        return( 1 );
660}
661
662static int msn_sb_message( gpointer data, char *msg, int msglen, char **cmd, int num_parts )
663{
664        struct msn_switchboard *sb = data;
665        struct im_connection *ic = sb->ic;
666        char *body;
667        int blen = 0;
668       
669        if( !num_parts )
670                return( 1 );
671       
672        if( ( body = strstr( msg, "\r\n\r\n" ) ) )
673        {
674                body += 4;
675                blen = msglen - ( body - msg );
676        }
677       
678        if( strcmp( cmd[0], "MSG" ) == 0 )
679        {
680                char *ct = msn_findheader( msg, "Content-Type:", msglen );
681               
682                if( !ct )
683                        return( 1 );
684               
685                if( g_strncasecmp( ct, "text/plain", 10 ) == 0 )
686                {
687                        g_free( ct );
688                       
689                        if( !body )
690                                return( 1 );
691                       
692                        if( sb->who )
693                        {
694                                imcb_buddy_msg( ic, cmd[1], body, 0, 0 );
695                        }
696                        else if( sb->chat )
697                        {
698                                imcb_chat_msg( sb->chat, cmd[1], body, 0, 0 );
699                        }
700                        else
701                        {
702                                /* PANIC! */
703                        }
704                }
705                else if( g_strncasecmp( ct, "text/x-msmsgsinvite", 19 ) == 0 )
706                {
707                        char *command = msn_findheader( body, "Invitation-Command:", blen );
708                        char *cookie = msn_findheader( body, "Invitation-Cookie:", blen );
709                        unsigned int icookie;
710                       
711                        g_free( ct );
712                       
713                        /* Every invite should have both a Command and Cookie header */
714                        if( !command || !cookie ) {
715                                g_free( command );
716                                g_free( cookie );
717                                imcb_log( ic, "Warning: No command or cookie from %s", sb->who );
718                                return 1;
719                        }
720                       
721                        icookie = strtoul( cookie, NULL, 10 );
722                        g_free( cookie );
723                       
724                        if( g_strncasecmp( command, "INVITE", 6 ) == 0 ) {
725                                msn_invitation_invite( sb, cmd[1], icookie, body, blen );
726                        } else if( g_strncasecmp( command, "ACCEPT", 6 ) == 0 ) {
727                                msn_invitation_accept( sb, cmd[1], icookie, body, blen );
728                        } else if( g_strncasecmp( command, "CANCEL", 6 ) == 0 ) {
729                                msn_invitation_cancel( sb, cmd[1], icookie, body, blen );
730                        } else {
731                                imcb_log( ic, "Warning: Received invalid invitation with "
732                                                "command %s from %s", command, sb->who );
733                        }
734                       
735                        g_free( command );
736                }
737                else if( g_strncasecmp( ct, "application/x-msnmsgrp2p", 24 ) == 0 ) 
738                {
739                        imcb_error( sb->ic, "Cannot receive file from %s: BitlBee does not "
740                                        "support msnmsgrp2p yet.", sb->who );
741                        g_free( ct );
742                }
743                else if( g_strncasecmp( ct, "text/x-msmsgscontrol", 20 ) == 0 )
744                {
745                        char *who = msn_findheader( msg, "TypingUser:", msglen );
746                       
747                        if( who )
748                        {
749                                imcb_buddy_typing( ic, who, OPT_TYPING );
750                                g_free( who );
751                        }
752                       
753                        g_free( ct );
754                }
755                else
756                {
757                        g_free( ct );
758                }
759        }
760       
761        return( 1 );
762}
763
764static gboolean msn_sb_keepalive( gpointer data, gint source, b_input_condition cond )
765{
766        struct msn_switchboard *sb = data;
767        return sb->ready && msn_sb_sendmessage( sb, SB_KEEPALIVE_MESSAGE );
768}
769
770void msn_sb_start_keepalives( struct msn_switchboard *sb, gboolean initial )
771{
772        struct buddy *b;
773       
774        if( sb && sb->who && sb->keepalive == 0 &&
775            ( b = imcb_find_buddy( sb->ic, sb->who ) ) && !b->present &&
776            set_getbool( &sb->ic->acc->set, "switchboard_keepalives" ) )
777        {
778                if( initial )
779                        msn_sb_keepalive( sb, 0, 0 );
780               
781                sb->keepalive = b_timeout_add( 20000, msn_sb_keepalive, sb );
782        }
783}
784
785void msn_sb_stop_keepalives( struct msn_switchboard *sb )
786{
787        if( sb && sb->keepalive > 0 )
788        {
789                b_event_remove( sb->keepalive );
790                sb->keepalive = 0;
791        }
792}
Note: See TracBrowser for help on using the repository browser.