source: protocols/msn/sb.c @ 13c1a9f

Last change on this file since 13c1a9f was e5abfd4, checked in by Wilmer van der Gaast <wilmer@…>, at 2010-05-09T11:26:57Z

Safety check for yesterday's fixes: Double-check that a groupchat struct
isn't claimed already.

  • Property mode set to 100644
File size: 18.6 KB
Line 
1  /********************************************************************\
2  * BitlBee -- An IRC to other IM-networks gateway                     *
3  *                                                                    *
4  * Copyright 2002-2005 Wilmer van der Gaast and others                *
5  \********************************************************************/
6
7/* MSN module - Switchboard server callbacks and utilities              */
8
9/*
10  This program is free software; you can redistribute it and/or modify
11  it under the terms of the GNU General Public License as published by
12  the Free Software Foundation; either version 2 of the License, or
13  (at your option) any later version.
14
15  This program is distributed in the hope that it will be useful,
16  but WITHOUT ANY WARRANTY; without even the implied warranty of
17  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  GNU General Public License for more details.
19
20  You should have received a copy of the GNU General Public License with
21  the Debian GNU/Linux distribution in /usr/share/common-licenses/GPL;
22  if not, write to the Free Software Foundation, Inc., 59 Temple Place,
23  Suite 330, Boston, MA  02111-1307  USA
24*/
25
26#include <ctype.h>
27#include "nogaim.h"
28#include "msn.h"
29#include "passport.h"
30#include "md5.h"
31#include "invitation.h"
32
33static gboolean msn_sb_callback( gpointer data, gint source, b_input_condition cond );
34static int msn_sb_command( gpointer data, char **cmd, int num_parts );
35static int msn_sb_message( gpointer data, char *msg, int msglen, char **cmd, int num_parts );
36
37int msn_sb_write( struct msn_switchboard *sb, char *s, int len )
38{
39        int st;
40       
41        st = write( sb->fd, s, len );
42        if( st != len )
43        {
44                msn_sb_destroy( sb );
45                return( 0 );
46        }
47       
48        return( 1 );
49}
50
51int msn_sb_write_msg( struct im_connection *ic, struct msn_message *m )
52{
53        struct msn_data *md = ic->proto_data;
54        struct msn_switchboard *sb;
55        char buf[1024];
56
57        /* FIXME: *CHECK* the reliability of using spare sb's! */
58        if( ( sb = msn_sb_spare( ic ) ) )
59        {
60                debug( "Trying to use a spare switchboard to message %s", m->who );
61               
62                sb->who = g_strdup( m->who );
63                g_snprintf( buf, sizeof( buf ), "CAL %d %s\r\n", ++sb->trId, m->who );
64                if( msn_sb_write( sb, buf, strlen( buf ) ) )
65                {
66                        /* He/She should join the switchboard soon, let's queue the message. */
67                        sb->msgq = g_slist_append( sb->msgq, m );
68                        return( 1 );
69                }
70        }
71       
72        debug( "Creating a new switchboard to message %s", m->who );
73       
74        /* If we reach this line, there was no spare switchboard, so let's make one. */
75        g_snprintf( buf, sizeof( buf ), "XFR %d SB\r\n", ++md->trId );
76        if( !msn_write( ic, buf, strlen( buf ) ) )
77        {
78                g_free( m->who );
79                g_free( m->text );
80                g_free( m );
81               
82                return( 0 );
83        }
84       
85        /* And queue the message to md. We'll pick it up when the switchboard comes up. */
86        md->msgq = g_slist_append( md->msgq, m );
87       
88        /* FIXME: If the switchboard creation fails, the message will not be sent. */
89       
90        return( 1 );
91}
92
93struct msn_switchboard *msn_sb_create( struct im_connection *ic, char *host, int port, char *key, int session )
94{
95        struct msn_data *md = ic->proto_data;
96        struct msn_switchboard *sb = g_new0( struct msn_switchboard, 1 );
97       
98        sb->fd = proxy_connect( host, port, msn_sb_connected, sb );
99        if( sb->fd < 0 )
100        {
101                g_free( sb );
102                return( NULL );
103        }
104       
105        sb->ic = ic;
106        sb->key = g_strdup( key );
107        sb->session = session;
108       
109        msn_switchboards = g_slist_append( msn_switchboards, sb );
110        md->switchboards = g_slist_append( md->switchboards, sb );
111       
112        return( sb );
113}
114
115struct msn_switchboard *msn_sb_by_handle( struct im_connection *ic, char *handle )
116{
117        struct msn_data *md = ic->proto_data;
118        struct msn_switchboard *sb;
119        GSList *l;
120       
121        for( l = md->switchboards; l; l = l->next )
122        {
123                sb = l->data;
124                if( sb->who && strcmp( sb->who, handle ) == 0 )
125                        return( sb );
126        }
127       
128        return( NULL );
129}
130
131struct msn_switchboard *msn_sb_by_chat( struct groupchat *c )
132{
133        struct msn_data *md = c->ic->proto_data;
134        struct msn_switchboard *sb;
135        GSList *l;
136       
137        for( l = md->switchboards; l; l = l->next )
138        {
139                sb = l->data;
140                if( sb->chat == c )
141                        return( sb );
142        }
143       
144        return( NULL );
145}
146
147struct msn_switchboard *msn_sb_spare( struct im_connection *ic )
148{
149        struct msn_data *md = ic->proto_data;
150        struct msn_switchboard *sb;
151        GSList *l;
152       
153        for( l = md->switchboards; l; l = l->next )
154        {
155                sb = l->data;
156                if( !sb->who && !sb->chat )
157                        return( sb );
158        }
159       
160        return( NULL );
161}
162
163int msn_sb_sendmessage( struct msn_switchboard *sb, char *text )
164{
165        if( sb->ready )
166        {
167                char *packet, *buf;
168                int i, j;
169               
170                /* Build the message. Convert LF to CR-LF for normal messages. */
171                if( strcmp( text, TYPING_NOTIFICATION_MESSAGE ) == 0 )
172                {
173                        i = strlen( MSN_TYPING_HEADERS ) + strlen( sb->ic->acc->user );
174                        buf = g_new0( char, i );
175                        i = g_snprintf( buf, i, MSN_TYPING_HEADERS, sb->ic->acc->user );
176                }
177                else if( strcmp( text, SB_KEEPALIVE_MESSAGE ) == 0 )
178                {
179                        buf = g_strdup( SB_KEEPALIVE_HEADERS );
180                        i = strlen( buf );
181                }
182                else if( strncmp( text, MSN_INVITE_HEADERS, sizeof( MSN_INVITE_HEADERS ) - 1 ) == 0 ) 
183                {
184                        buf = g_strdup( text );
185                        i = strlen( buf );
186                }
187                else
188                {
189                        buf = g_new0( char, sizeof( MSN_MESSAGE_HEADERS ) + strlen( text ) * 2 + 1 );
190                        i = strlen( MSN_MESSAGE_HEADERS );
191                       
192                        strcpy( buf, MSN_MESSAGE_HEADERS );
193                        for( j = 0; text[j]; j ++ )
194                        {
195                                if( text[j] == '\n' )
196                                        buf[i++] = '\r';
197                               
198                                buf[i++] = text[j];
199                        }
200                }
201               
202                /* Build the final packet (MSG command + the message). */
203                packet = g_strdup_printf( "MSG %d N %d\r\n%s", ++sb->trId, i, buf );
204                g_free( buf );
205                if( msn_sb_write( sb, packet, strlen( packet ) ) )
206                {
207                        g_free( packet );
208                        return( 1 );
209                }
210                else
211                {
212                        g_free( packet );
213                        return( 0 );
214                }
215        }
216        else if( sb->who )
217        {
218                struct msn_message *m = g_new0( struct msn_message, 1 );
219               
220                m->who = g_strdup( "" );
221                m->text = g_strdup( text );
222                sb->msgq = g_slist_append( sb->msgq, m );
223               
224                return( 1 );
225        }
226        else
227        {
228                return( 0 );
229        }
230}
231
232struct groupchat *msn_sb_to_chat( struct msn_switchboard *sb )
233{
234        struct im_connection *ic = sb->ic;
235        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, GAIM_INPUT_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        {
344                time_t now = time( NULL );
345               
346                if( now - md->first_sb_failure > 600 )
347                {
348                        /* It's not really the first one, but the start of this "series".
349                           With this, the warning below will be shown only if this happens
350                           at least three times in ten minutes. This algorithm isn't
351                           perfect, but for this purpose it will do. */
352                        md->first_sb_failure = now;
353                        md->sb_failures = 0;
354                }
355               
356                debug( "Error: Switchboard died" );
357                if( ++ md->sb_failures >= 3 )
358                        imcb_log( ic, "Warning: Many switchboard failures on MSN connection. "
359                                      "There might be problems delivering your messages." );
360               
361                if( sb->msgq != NULL )
362                {
363                        char buf[1024];
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, creating a new switchboard to retry." );
379                        g_snprintf( buf, sizeof( buf ), "XFR %d SB\r\n", ++md->trId );
380                        if( !msn_write( ic, buf, strlen( buf ) ) )
381                                return FALSE;
382                }
383               
384                msn_sb_destroy( sb );
385               
386                return FALSE;
387        }
388        else
389        {
390                return TRUE;
391        }
392}
393
394static int msn_sb_command( gpointer data, char **cmd, int num_parts )
395{
396        struct msn_switchboard *sb = data;
397        struct im_connection *ic = sb->ic;
398        char buf[1024];
399       
400        if( !num_parts )
401        {
402                /* Hrrm... Empty command...? Ignore? */
403                return( 1 );
404        }
405       
406        if( strcmp( cmd[0], "XFR" ) == 0 )
407        {
408                imcb_error( ic, "Received an XFR from a switchboard server, unable to comply! This is likely to be a bug, please report it!" );
409                imc_logout( ic, TRUE );
410                return( 0 );
411        }
412        else if( strcmp( cmd[0], "USR" ) == 0 )
413        {
414                if( num_parts != 5 )
415                {
416                        msn_sb_destroy( sb );
417                        return( 0 );
418                }
419               
420                if( strcmp( cmd[2], "OK" ) != 0 )
421                {
422                        msn_sb_destroy( sb );
423                        return( 0 );
424                }
425               
426                if( sb->who )
427                {
428                        g_snprintf( buf, sizeof( buf ), "CAL %d %s\r\n", ++sb->trId, sb->who );
429                        return( msn_sb_write( sb, buf, strlen( buf ) ) );
430                }
431                else
432                {
433                        debug( "Just created a switchboard, but I don't know what to do with it." );
434                }
435        }
436        else if( strcmp( cmd[0], "IRO" ) == 0 )
437        {
438                int num, tot;
439               
440                if( num_parts != 6 )
441                {
442                        msn_sb_destroy( sb );
443                        return( 0 );
444                }
445               
446                num = atoi( cmd[2] );
447                tot = atoi( cmd[3] );
448               
449                if( tot <= 0 )
450                {
451                        msn_sb_destroy( sb );
452                        return( 0 );
453                }
454                else if( tot > 1 )
455                {
456                        char buf[1024];
457                       
458                        if( num == 1 )
459                        {
460                                g_snprintf( buf, sizeof( buf ), "MSN groupchat session %d", sb->session );
461                                sb->chat = imcb_chat_new( ic, buf );
462                               
463                                g_free( sb->who );
464                                sb->who = NULL;
465                        }
466                       
467                        imcb_chat_add_buddy( sb->chat, cmd[4] );
468                       
469                        if( num == tot )
470                        {
471                                imcb_chat_add_buddy( sb->chat, ic->acc->user );
472                        }
473                }
474        }
475        else if( strcmp( cmd[0], "ANS" ) == 0 )
476        {
477                if( num_parts != 3 )
478                {
479                        msn_sb_destroy( sb );
480                        return( 0 );
481                }
482               
483                if( strcmp( cmd[2], "OK" ) != 0 )
484                {
485                        debug( "Switchboard server sent a negative ANS reply" );
486                        msn_sb_destroy( sb );
487                        return( 0 );
488                }
489               
490                sb->ready = 1;
491               
492                msn_sb_start_keepalives( sb, FALSE );
493        }
494        else if( strcmp( cmd[0], "CAL" ) == 0 )
495        {
496                if( num_parts != 4 || !isdigit( cmd[3][0] ) )
497                {
498                        msn_sb_destroy( sb );
499                        return( 0 );
500                }
501               
502                sb->session = atoi( cmd[3] );
503        }
504        else if( strcmp( cmd[0], "JOI" ) == 0 )
505        {
506                if( num_parts != 3 )
507                {
508                        msn_sb_destroy( sb );
509                        return( 0 );
510                }
511               
512                if( sb->who && g_strcasecmp( cmd[1], sb->who ) == 0 )
513                {
514                        /* The user we wanted to talk to is finally there, let's send the queued messages then. */
515                        struct msn_message *m;
516                        GSList *l;
517                        int st = 1;
518                       
519                        debug( "%s arrived in the switchboard session, now sending queued message(s)", cmd[1] );
520                       
521                        /* Without this, sendmessage() will put everything back on the queue... */
522                        sb->ready = 1;
523                       
524                        while( ( l = sb->msgq ) )
525                        {
526                                m = l->data;
527                                if( st )
528                                {
529                                        /* This hack is meant to convert a regular new chat into a groupchat */
530                                        if( strcmp( m->text, GROUPCHAT_SWITCHBOARD_MESSAGE ) == 0 )
531                                                msn_sb_to_chat( sb );
532                                        else
533                                                st = msn_sb_sendmessage( sb, m->text );
534                                }
535                                g_free( m->text );
536                                g_free( m->who );
537                                g_free( m );
538                               
539                                sb->msgq = g_slist_remove( sb->msgq, m );
540                        }
541                       
542                        msn_sb_start_keepalives( sb, FALSE );
543                       
544                        return( st );
545                }
546                else if( sb->who )
547                {
548                        debug( "Converting chat with %s to a groupchat because %s joined the session.", sb->who, cmd[1] );
549                       
550                        /* This SB is a one-to-one chat right now, but someone else is joining. */
551                        msn_sb_to_chat( sb );
552                       
553                        imcb_chat_add_buddy( sb->chat, cmd[1] );
554                }
555                else if( sb->chat )
556                {
557                        imcb_chat_add_buddy( sb->chat, cmd[1] );
558                        sb->ready = 1;
559                }
560                else
561                {
562                        /* PANIC! */
563                }
564        }
565        else if( strcmp( cmd[0], "MSG" ) == 0 )
566        {
567                if( num_parts != 4 )
568                {
569                        msn_sb_destroy( sb );
570                        return( 0 );
571                }
572               
573                sb->handler->msglen = atoi( cmd[3] );
574               
575                if( sb->handler->msglen <= 0 )
576                {
577                        debug( "Received a corrupted message on the switchboard, the switchboard will be closed" );
578                        msn_sb_destroy( sb );
579                        return( 0 );
580                }
581        }
582        else if( strcmp( cmd[0], "NAK" ) == 0 )
583        {
584                if( sb->who )
585                {
586                        imcb_log( ic, "The MSN servers could not deliver one of your messages to %s.", sb->who );
587                }
588                else
589                {
590                        imcb_log( ic, "The MSN servers could not deliver one of your groupchat messages to all participants." );
591                }
592        }
593        else if( strcmp( cmd[0], "BYE" ) == 0 )
594        {
595                if( num_parts < 2 )
596                {
597                        msn_sb_destroy( sb );
598                        return( 0 );
599                }
600               
601                /* if( cmd[2] && *cmd[2] == '1' ) -=> Chat is being cleaned up because of idleness */
602               
603                if( sb->who )
604                {
605                        msn_sb_stop_keepalives( sb );
606                       
607                        /* This is a single-person chat, and the other person is leaving. */
608                        g_free( sb->who );
609                        sb->who = NULL;
610                        sb->ready = 0;
611                       
612                        debug( "Person %s left the one-to-one switchboard connection. Keeping it around as a spare...", cmd[1] );
613                       
614                        /* We could clean up the switchboard now, but keeping it around
615                           as a spare for a next conversation sounds more sane to me.
616                           The server will clean it up when it's idle for too long. */
617                }
618                else if( sb->chat )
619                {
620                        imcb_chat_remove_buddy( sb->chat, cmd[1], "" );
621                }
622                else
623                {
624                        /* PANIC! */
625                }
626        }
627        else if( isdigit( cmd[0][0] ) )
628        {
629                int num = atoi( cmd[0] );
630                const struct msn_status_code *err = msn_status_by_number( num );
631               
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.