source: protocols/msn/sb.c @ 2528cda

Last change on this file since 2528cda was 2528cda, checked in by Wilmer van der Gaast <wilmer@…>, at 2010-08-08T15:34:49Z

Merging msn-offline branch. A tiny bit of MSNP13, and it works for the first
minute of the session (after that the MSN server finds out the rest of
BitlBee still speaks MSNP8).

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