source: protocols/msn/sb.c @ 5fecede

Last change on this file since 5fecede was 5fecede, checked in by Wilmer van der Gaast <wilmer@…>, at 2010-08-08T17:29:43Z

Enough changes to successfully login up to (but not including) fetching the
contact list.

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