source: protocols/msn/sb.c @ e0a0a42

Last change on this file since e0a0a42 was 9b0ad7e, checked in by Wilmer van der Gaast <wilmer@…>, at 2011-12-19T00:00:31Z

Moving msn_findheader() to lib/misc.c as get_rfc822_header() so I can use it
in OAuth as well. (Need it to find the Content-Type: header.)

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