source: protocols/msn/sb.c @ b556e46

Last change on this file since b556e46 was 4aa0f6b, checked in by Wilmer van der Gaast <wilmer@…>, at 2010-06-07T14:31:07Z

Merging killerbee stuff, bringing all the bleeding-edge stuff together.

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