source: protocols/msn/sb.c @ f8ec890

Last change on this file since f8ec890 was f8cb76d, checked in by Wilmer van der Gaast <wilmer@…>, at 2010-05-11T21:33:37Z

Stop those "Many switchboard failures" messages. No point in showing them
unless the lost switchboard actually had something queued.

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