source: protocols/msn/sb.c @ bd5eee3

Last change on this file since bd5eee3 was 36577aa, checked in by Wilmer van der Gaast <wilmer@…>, at 2010-05-09T00:28:38Z

Create the struct groupchat early on in msn_chat_with() so the new chat
setup method works properly.

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