source: protocols/msn/sb.c @ b46769d

Last change on this file since b46769d was b46769d, checked in by Wilmer van der Gaast <wilmer@…>, at 2010-08-12T22:44:56Z

Some syntax checking fixups; don't make the same mistake of failing just if
the MSN server is sending a little bit *more* info.
And adding xt_insert_node() used in the ADL generation code.

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