source: protocols/msn/sb.c @ c0f33f1

Last change on this file since c0f33f1 was 9c84617, checked in by Wilmer van der Gaast <wilmer@…>, at 2010-12-13T00:42:58Z

Silently adding /CTCP NUDGE support for MSN contacts.

  • Property mode set to 100644
File size: 18.8 KB
Line 
1  /********************************************************************\
2  * BitlBee -- An IRC to other IM-networks gateway                     *
3  *                                                                    *
4  * Copyright 2002-2010 Wilmer van der Gaast and others                *
5  \********************************************************************/
6
7/* MSN module - Switchboard server callbacks and utilities              */
8
9/*
10  This program is free software; you can redistribute it and/or modify
11  it under the terms of the GNU General Public License as published by
12  the Free Software Foundation; either version 2 of the License, or
13  (at your option) any later version.
14
15  This program is distributed in the hope that it will be useful,
16  but WITHOUT ANY WARRANTY; without even the implied warranty of
17  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  GNU General Public License for more details.
19
20  You should have received a copy of the GNU General Public License with
21  the Debian GNU/Linux distribution in /usr/share/common-licenses/GPL;
22  if not, write to the Free Software Foundation, Inc., 59 Temple Place,
23  Suite 330, Boston, MA  02111-1307  USA
24*/
25
26#include <ctype.h>
27#include "nogaim.h"
28#include "msn.h"
29#include "md5.h"
30#include "soap.h"
31#include "invitation.h"
32
33static gboolean msn_sb_callback( gpointer data, gint source, b_input_condition cond );
34static int msn_sb_command( 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        struct msn_data *md;
311        char buf[1024];
312       
313        /* Are we still alive? */
314        if( !g_slist_find( msn_switchboards, sb ) )
315                return FALSE;
316       
317        ic = sb->ic;
318        md = ic->proto_data;
319       
320        if( source != sb->fd )
321        {
322                debug( "Error %d while connecting to switchboard server", 1 );
323                msn_sb_destroy( sb );
324                return FALSE;
325        }
326       
327        /* Prepare the callback */
328        sb->handler = g_new0( struct msn_handler_data, 1 );
329        sb->handler->fd = sb->fd;
330        sb->handler->rxq = g_new0( char, 1 );
331        sb->handler->data = sb;
332        sb->handler->exec_command = msn_sb_command;
333        sb->handler->exec_message = msn_sb_message;
334       
335        if( sb->session == MSN_SB_NEW )
336                g_snprintf( buf, sizeof( buf ), "USR %d %s %s\r\n", ++sb->trId, ic->acc->user, sb->key );
337        else
338                g_snprintf( buf, sizeof( buf ), "ANS %d %s %s %d\r\n", ++sb->trId, ic->acc->user, sb->key, sb->session );
339       
340        if( msn_sb_write( sb, "%s", buf ) )
341                sb->inp = b_input_add( sb->fd, B_EV_IO_READ, msn_sb_callback, sb );
342        else
343                debug( "Error %d while connecting to switchboard server", 2 );
344       
345        return FALSE;
346}
347
348static gboolean msn_sb_callback( gpointer data, gint source, b_input_condition cond )
349{
350        struct msn_switchboard *sb = data;
351        struct im_connection *ic = sb->ic;
352        struct msn_data *md = ic->proto_data;
353       
354        if( msn_handler( sb->handler ) != -1 )
355                return TRUE;
356       
357        if( sb->msgq != NULL )
358        {
359                time_t now = time( NULL );
360               
361                if( now - md->first_sb_failure > 600 )
362                {
363                        /* It's not really the first one, but the start of this "series".
364                           With this, the warning below will be shown only if this happens
365                           at least three times in ten minutes. This algorithm isn't
366                           perfect, but for this purpose it will do. */
367                        md->first_sb_failure = now;
368                        md->sb_failures = 0;
369                }
370               
371                debug( "Error: Switchboard died" );
372                if( ++ md->sb_failures >= 3 )
373                        imcb_log( ic, "Warning: Many switchboard failures on MSN connection. "
374                                      "There might be problems delivering your messages." );
375               
376                if( md->msgq == NULL )
377                {
378                        md->msgq = sb->msgq;
379                }
380                else
381                {
382                        GSList *l;
383                       
384                        for( l = md->msgq; l->next; l = l->next );
385                        l->next = sb->msgq;
386                }
387                sb->msgq = NULL;
388               
389                debug( "Moved queued messages back to the main queue, "
390                       "creating a new switchboard to retry." );
391                if( !msn_ns_write( ic, -1, "XFR %d SB\r\n", ++md->trId ) )
392                        return FALSE;
393        }
394       
395        msn_sb_destroy( sb );
396        return FALSE;
397}
398
399static int msn_sb_command( struct msn_handler_data *handler, char **cmd, int num_parts )
400{
401        struct msn_switchboard *sb = handler->data;
402        struct im_connection *ic = sb->ic;
403       
404        if( !num_parts )
405        {
406                /* Hrrm... Empty command...? Ignore? */
407                return( 1 );
408        }
409       
410        if( strcmp( cmd[0], "XFR" ) == 0 )
411        {
412                imcb_error( ic, "Received an XFR from a switchboard server, unable to comply! This is likely to be a bug, please report it!" );
413                imc_logout( ic, TRUE );
414                return( 0 );
415        }
416        else if( strcmp( cmd[0], "USR" ) == 0 )
417        {
418                if( num_parts < 5 )
419                {
420                        msn_sb_destroy( sb );
421                        return( 0 );
422                }
423               
424                if( strcmp( cmd[2], "OK" ) != 0 )
425                {
426                        msn_sb_destroy( sb );
427                        return( 0 );
428                }
429               
430                if( sb->who )
431                        return msn_sb_write( sb, "CAL %d %s\r\n", ++sb->trId, sb->who );
432                else
433                        debug( "Just created a switchboard, but I don't know what to do with it." );
434        }
435        else if( strcmp( cmd[0], "IRO" ) == 0 )
436        {
437                int num, tot;
438               
439                if( num_parts < 6 )
440                {
441                        msn_sb_destroy( sb );
442                        return( 0 );
443                }
444               
445                num = atoi( cmd[2] );
446                tot = atoi( cmd[3] );
447               
448                if( tot <= 0 )
449                {
450                        msn_sb_destroy( sb );
451                        return( 0 );
452                }
453                else if( tot > 1 )
454                {
455                        char buf[1024];
456                       
457                        if( num == 1 )
458                        {
459                                g_snprintf( buf, sizeof( buf ), "MSN groupchat session %d", sb->session );
460                                sb->chat = imcb_chat_new( ic, buf );
461                               
462                                g_free( sb->who );
463                                sb->who = NULL;
464                        }
465                       
466                        imcb_chat_add_buddy( sb->chat, cmd[4] );
467                       
468                        if( num == tot )
469                        {
470                                imcb_chat_add_buddy( sb->chat, ic->acc->user );
471                        }
472                }
473        }
474        else if( strcmp( cmd[0], "ANS" ) == 0 )
475        {
476                if( num_parts < 3 )
477                {
478                        msn_sb_destroy( sb );
479                        return( 0 );
480                }
481               
482                if( strcmp( cmd[2], "OK" ) != 0 )
483                {
484                        debug( "Switchboard server sent a negative ANS reply" );
485                        msn_sb_destroy( sb );
486                        return( 0 );
487                }
488               
489                sb->ready = 1;
490               
491                msn_sb_start_keepalives( sb, FALSE );
492        }
493        else if( strcmp( cmd[0], "CAL" ) == 0 )
494        {
495                if( num_parts < 4 || !isdigit( cmd[3][0] ) )
496                {
497                        msn_sb_destroy( sb );
498                        return( 0 );
499                }
500               
501                sb->session = atoi( cmd[3] );
502        }
503        else if( strcmp( cmd[0], "JOI" ) == 0 )
504        {
505                if( num_parts < 3 )
506                {
507                        msn_sb_destroy( sb );
508                        return( 0 );
509                }
510               
511                if( sb->who && g_strcasecmp( cmd[1], sb->who ) == 0 )
512                {
513                        /* The user we wanted to talk to is finally there, let's send the queued messages then. */
514                        struct msn_message *m;
515                        GSList *l;
516                        int st = 1;
517                       
518                        debug( "%s arrived in the switchboard session, now sending queued message(s)", cmd[1] );
519                       
520                        /* Without this, sendmessage() will put everything back on the queue... */
521                        sb->ready = 1;
522                       
523                        while( ( l = sb->msgq ) )
524                        {
525                                m = l->data;
526                                if( st )
527                                {
528                                        /* This hack is meant to convert a regular new chat into a groupchat */
529                                        if( strcmp( m->text, GROUPCHAT_SWITCHBOARD_MESSAGE ) == 0 )
530                                                msn_sb_to_chat( sb );
531                                        else
532                                                st = msn_sb_sendmessage( sb, m->text );
533                                }
534                                g_free( m->text );
535                                g_free( m->who );
536                                g_free( m );
537                               
538                                sb->msgq = g_slist_remove( sb->msgq, m );
539                        }
540                       
541                        msn_sb_start_keepalives( sb, FALSE );
542                       
543                        return( st );
544                }
545                else if( sb->who )
546                {
547                        debug( "Converting chat with %s to a groupchat because %s joined the session.", sb->who, cmd[1] );
548                       
549                        /* This SB is a one-to-one chat right now, but someone else is joining. */
550                        msn_sb_to_chat( sb );
551                       
552                        imcb_chat_add_buddy( sb->chat, cmd[1] );
553                }
554                else if( sb->chat )
555                {
556                        imcb_chat_add_buddy( sb->chat, cmd[1] );
557                        sb->ready = 1;
558                }
559                else
560                {
561                        /* PANIC! */
562                }
563        }
564        else if( strcmp( cmd[0], "MSG" ) == 0 )
565        {
566                if( num_parts < 4 )
567                {
568                        msn_sb_destroy( sb );
569                        return( 0 );
570                }
571               
572                sb->handler->msglen = atoi( cmd[3] );
573               
574                if( sb->handler->msglen <= 0 )
575                {
576                        debug( "Received a corrupted message on the switchboard, the switchboard will be closed" );
577                        msn_sb_destroy( sb );
578                        return( 0 );
579                }
580        }
581        else if( strcmp( cmd[0], "NAK" ) == 0 )
582        {
583                if( sb->who )
584                {
585                        imcb_log( ic, "The MSN servers could not deliver one of your messages to %s.", sb->who );
586                }
587                else
588                {
589                        imcb_log( ic, "The MSN servers could not deliver one of your groupchat messages to all participants." );
590                }
591        }
592        else if( strcmp( cmd[0], "BYE" ) == 0 )
593        {
594                if( num_parts < 2 )
595                {
596                        msn_sb_destroy( sb );
597                        return( 0 );
598                }
599               
600                /* if( cmd[2] && *cmd[2] == '1' ) -=> Chat is being cleaned up because of idleness */
601               
602                if( sb->who )
603                {
604                        msn_sb_stop_keepalives( sb );
605                       
606                        /* This is a single-person chat, and the other person is leaving. */
607                        g_free( sb->who );
608                        sb->who = NULL;
609                        sb->ready = 0;
610                       
611                        debug( "Person %s left the one-to-one switchboard connection. Keeping it around as a spare...", cmd[1] );
612                       
613                        /* We could clean up the switchboard now, but keeping it around
614                           as a spare for a next conversation sounds more sane to me.
615                           The server will clean it up when it's idle for too long. */
616                }
617                else if( sb->chat )
618                {
619                        imcb_chat_remove_buddy( sb->chat, cmd[1], "" );
620                }
621                else
622                {
623                        /* PANIC! */
624                }
625        }
626        else if( isdigit( cmd[0][0] ) )
627        {
628                int num = atoi( cmd[0] );
629                const struct msn_status_code *err = msn_status_by_number( num );
630               
631                /* If the person is offline, send an offline message instead,
632                   and don't report an error. */
633                if( num == 217 )
634                        msn_soap_oim_send_queue( ic, &sb->msgq );
635                else
636                        imcb_error( ic, "Error reported by switchboard server: %s", err->text );
637               
638                if( err->flags & STATUS_SB_FATAL )
639                {
640                        msn_sb_destroy( sb );
641                        return 0;
642                }
643                else if( err->flags & STATUS_FATAL )
644                {
645                        imc_logout( ic, TRUE );
646                        return 0;
647                }
648                else if( err->flags & STATUS_SB_IM_SPARE )
649                {
650                        if( sb->who )
651                        {
652                                /* Apparently some invitation failed. We might want to use this
653                                   board later, so keep it as a spare. */
654                                g_free( sb->who );
655                                sb->who = NULL;
656                               
657                                /* Also clear the msgq, otherwise someone else might get them. */
658                                msn_msgq_purge( ic, &sb->msgq );
659                        }
660                       
661                        /* Do NOT return 0 here, we want to keep this sb. */
662                }
663        }
664        else
665        {
666                /* debug( "Received unknown command from switchboard server: %s", cmd[0] ); */
667        }
668       
669        return( 1 );
670}
671
672static int msn_sb_message( struct msn_handler_data *handler, char *msg, int msglen, char **cmd, int num_parts )
673{
674        struct msn_switchboard *sb = handler->data;
675        struct im_connection *ic = sb->ic;
676        char *body;
677        int blen = 0;
678       
679        if( !num_parts )
680                return( 1 );
681       
682        if( ( body = strstr( msg, "\r\n\r\n" ) ) )
683        {
684                body += 4;
685                blen = msglen - ( body - msg );
686        }
687       
688        if( strcmp( cmd[0], "MSG" ) == 0 )
689        {
690                char *ct = msn_findheader( msg, "Content-Type:", msglen );
691               
692                if( !ct )
693                        return( 1 );
694               
695                if( g_strncasecmp( ct, "text/plain", 10 ) == 0 )
696                {
697                        g_free( ct );
698                       
699                        if( !body )
700                                return( 1 );
701                       
702                        if( sb->who )
703                        {
704                                imcb_buddy_msg( ic, cmd[1], body, 0, 0 );
705                        }
706                        else if( sb->chat )
707                        {
708                                imcb_chat_msg( sb->chat, cmd[1], body, 0, 0 );
709                        }
710                        else
711                        {
712                                /* PANIC! */
713                        }
714                }
715#if 0
716                // Disable MSN ft support for now.
717                else if( g_strncasecmp( ct, "text/x-msmsgsinvite", 19 ) == 0 )
718                {
719                        char *command = msn_findheader( body, "Invitation-Command:", blen );
720                        char *cookie = msn_findheader( body, "Invitation-Cookie:", blen );
721                        unsigned int icookie;
722                       
723                        g_free( ct );
724                       
725                        /* Every invite should have both a Command and Cookie header */
726                        if( !command || !cookie ) {
727                                g_free( command );
728                                g_free( cookie );
729                                imcb_log( ic, "Warning: No command or cookie from %s", sb->who );
730                                return 1;
731                        }
732                       
733                        icookie = strtoul( cookie, NULL, 10 );
734                        g_free( cookie );
735                       
736                        if( g_strncasecmp( command, "INVITE", 6 ) == 0 ) {
737                                msn_invitation_invite( sb, cmd[1], icookie, body, blen );
738                        } else if( g_strncasecmp( command, "ACCEPT", 6 ) == 0 ) {
739                                msn_invitation_accept( sb, cmd[1], icookie, body, blen );
740                        } else if( g_strncasecmp( command, "CANCEL", 6 ) == 0 ) {
741                                msn_invitation_cancel( sb, cmd[1], icookie, body, blen );
742                        } else {
743                                imcb_log( ic, "Warning: Received invalid invitation with "
744                                                "command %s from %s", command, sb->who );
745                        }
746                       
747                        g_free( command );
748                }
749#endif
750                else if( g_strncasecmp( ct, "application/x-msnmsgrp2p", 24 ) == 0 ) 
751                {
752                        /* Not currently implemented. Don't warn about it since
753                           this seems to be used for avatars now. */
754                        g_free( ct );
755                }
756                else if( g_strncasecmp( ct, "text/x-msmsgscontrol", 20 ) == 0 )
757                {
758                        char *who = msn_findheader( msg, "TypingUser:", msglen );
759                       
760                        if( who )
761                        {
762                                imcb_buddy_typing( ic, who, OPT_TYPING );
763                                g_free( who );
764                        }
765                       
766                        g_free( ct );
767                }
768                else
769                {
770                        g_free( ct );
771                }
772        }
773       
774        return( 1 );
775}
776
777static gboolean msn_sb_keepalive( gpointer data, gint source, b_input_condition cond )
778{
779        struct msn_switchboard *sb = data;
780        return sb->ready && msn_sb_sendmessage( sb, SB_KEEPALIVE_MESSAGE );
781}
782
783void msn_sb_start_keepalives( struct msn_switchboard *sb, gboolean initial )
784{
785        bee_user_t *bu;
786       
787        if( sb && sb->who && sb->keepalive == 0 &&
788            ( bu = bee_user_by_handle( sb->ic->bee, sb->ic, sb->who ) ) &&
789            !( bu->flags & BEE_USER_ONLINE ) &&
790            set_getbool( &sb->ic->acc->set, "switchboard_keepalives" ) )
791        {
792                if( initial )
793                        msn_sb_keepalive( sb, 0, 0 );
794               
795                sb->keepalive = b_timeout_add( 20000, msn_sb_keepalive, sb );
796        }
797}
798
799void msn_sb_stop_keepalives( struct msn_switchboard *sb )
800{
801        if( sb && sb->keepalive > 0 )
802        {
803                b_event_remove( sb->keepalive );
804                sb->keepalive = 0;
805        }
806}
Note: See TracBrowser for help on using the repository browser.