source: protocols/msn/sb.c @ 73efe3a

Last change on this file since 73efe3a was 4e4af1b, checked in by Wilmer van der Gaast <wilmer@…>, at 2010-08-14T08:48:46Z

Remove some old Passport stuff, this is all in soap.[ch] now.

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