source: protocols/msn/sb.c @ 6824fb3

Last change on this file since 6824fb3 was bb839e8, checked in by Wilmer van der Gaast <wilmer@…>, at 2010-04-10T01:05:39Z

Be more clever with keepalives; detect when a switchboard is opened with
someone who's offline already. Still a hack but it eases the pain a little
bit.

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