source: protocols/msn/ns.c @ e046390

Last change on this file since e046390 was e046390, checked in by Wilmer van der Gaast <wilmer@…>, at 2009-10-10T23:25:54Z

Make purple use BitlBee's event handling API. Since the APIs never really
diverged too much this is fairly transparent. I did rename and redefine
GAIM_INPUT_* variables to really make it work without adding another stupid
layer in between.

One problem left, the new libpurple input API doesn't care about return
values. Fixing that in the next CL.

  • Property mode set to 100644
File size: 17.5 KB
Line 
1  /********************************************************************\
2  * BitlBee -- An IRC to other IM-networks gateway                     *
3  *                                                                    *
4  * Copyright 2002-2004 Wilmer van der Gaast and others                *
5  \********************************************************************/
6
7/* MSN module - Notification server callbacks                           */
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
32static gboolean msn_ns_callback( gpointer data, gint source, b_input_condition cond );
33static int msn_ns_command( gpointer data, char **cmd, int num_parts );
34static int msn_ns_message( gpointer data, char *msg, int msglen, char **cmd, int num_parts );
35
36static void msn_auth_got_passport_token( struct msn_auth_data *mad );
37
38gboolean msn_ns_connected( gpointer data, gint source, b_input_condition cond )
39{
40        struct im_connection *ic = data;
41        struct msn_data *md;
42        char s[1024];
43       
44        if( !g_slist_find( msn_connections, ic ) )
45                return FALSE;
46       
47        if( source == -1 )
48        {
49                imcb_error( ic, "Could not connect to server" );
50                imc_logout( ic, TRUE );
51                return FALSE;
52        }
53       
54        md = ic->proto_data;
55       
56        if( !md->handler )
57        {
58                md->handler = g_new0( struct msn_handler_data, 1 );
59                md->handler->data = ic;
60                md->handler->exec_command = msn_ns_command;
61                md->handler->exec_message = msn_ns_message;
62        }
63        else
64        {
65                if( md->handler->rxq )
66                        g_free( md->handler->rxq );
67               
68                md->handler->rxlen = 0;
69        }
70       
71        md->handler->fd = md->fd;
72        md->handler->rxq = g_new0( char, 1 );
73       
74        g_snprintf( s, sizeof( s ), "VER %d MSNP8 CVR0\r\n", ++md->trId );
75        if( msn_write( ic, s, strlen( s ) ) )
76        {
77                ic->inpa = b_input_add( md->fd, B_EV_IO_READ, msn_ns_callback, ic );
78                imcb_log( ic, "Connected to server, waiting for reply" );
79        }
80       
81        return FALSE;
82}
83
84static gboolean msn_ns_callback( gpointer data, gint source, b_input_condition cond )
85{
86        struct im_connection *ic = data;
87        struct msn_data *md = ic->proto_data;
88       
89        if( msn_handler( md->handler ) == -1 ) /* Don't do this on ret == 0, it's already done then. */
90        {
91                imcb_error( ic, "Error while reading from server" );
92                imc_logout( ic, TRUE );
93               
94                return FALSE;
95        }
96        else
97                return TRUE;
98}
99
100static int msn_ns_command( gpointer data, char **cmd, int num_parts )
101{
102        struct im_connection *ic = data;
103        struct msn_data *md = ic->proto_data;
104        char buf[1024];
105       
106        if( num_parts == 0 )
107        {
108                /* Hrrm... Empty command...? Ignore? */
109                return( 1 );
110        }
111       
112        if( strcmp( cmd[0], "VER" ) == 0 )
113        {
114                if( cmd[2] && strncmp( cmd[2], "MSNP8", 5 ) != 0 )
115                {
116                        imcb_error( ic, "Unsupported protocol" );
117                        imc_logout( ic, FALSE );
118                        return( 0 );
119                }
120               
121                g_snprintf( buf, sizeof( buf ), "CVR %d 0x0409 mac 10.2.0 ppc macmsgs 3.5.1 macmsgs %s\r\n",
122                                                ++md->trId, ic->acc->user );
123                return( msn_write( ic, buf, strlen( buf ) ) );
124        }
125        else if( strcmp( cmd[0], "CVR" ) == 0 )
126        {
127                /* We don't give a damn about the information we just received */
128                g_snprintf( buf, sizeof( buf ), "USR %d TWN I %s\r\n", ++md->trId, ic->acc->user );
129                return( msn_write( ic, buf, strlen( buf ) ) );
130        }
131        else if( strcmp( cmd[0], "XFR" ) == 0 )
132        {
133                char *server;
134                int port;
135               
136                if( num_parts == 6 && strcmp( cmd[2], "NS" ) == 0 )
137                {
138                        b_event_remove( ic->inpa );
139                        ic->inpa = 0;
140                        closesocket( md->fd );
141                       
142                        server = strchr( cmd[3], ':' );
143                        if( !server )
144                        {
145                                imcb_error( ic, "Syntax error" );
146                                imc_logout( ic, TRUE );
147                                return( 0 );
148                        }
149                        *server = 0;
150                        port = atoi( server + 1 );
151                        server = cmd[3];
152                       
153                        imcb_log( ic, "Transferring to other server" );
154                       
155                        md->fd = proxy_connect( server, port, msn_ns_connected, ic );
156                }
157                else if( num_parts == 6 && strcmp( cmd[2], "SB" ) == 0 )
158                {
159                        struct msn_switchboard *sb;
160                       
161                        server = strchr( cmd[3], ':' );
162                        if( !server )
163                        {
164                                imcb_error( ic, "Syntax error" );
165                                imc_logout( ic, TRUE );
166                                return( 0 );
167                        }
168                        *server = 0;
169                        port = atoi( server + 1 );
170                        server = cmd[3];
171                       
172                        if( strcmp( cmd[4], "CKI" ) != 0 )
173                        {
174                                imcb_error( ic, "Unknown authentication method for switchboard" );
175                                imc_logout( ic, TRUE );
176                                return( 0 );
177                        }
178                       
179                        debug( "Connecting to a new switchboard with key %s", cmd[5] );
180
181                        if( ( sb = msn_sb_create( ic, server, port, cmd[5], MSN_SB_NEW ) ) == NULL )
182                        {
183                                /* Although this isn't strictly fatal for the NS connection, it's
184                                   definitely something serious (we ran out of file descriptors?). */
185                                imcb_error( ic, "Could not create new switchboard" );
186                                imc_logout( ic, TRUE );
187                                return( 0 );
188                        }
189                       
190                        if( md->msgq )
191                        {
192                                struct msn_message *m = md->msgq->data;
193                                GSList *l;
194                               
195                                sb->who = g_strdup( m->who );
196                               
197                                /* Move all the messages to the first user in the message
198                                   queue to the switchboard message queue. */
199                                l = md->msgq;
200                                while( l )
201                                {
202                                        m = l->data;
203                                        l = l->next;
204                                        if( strcmp( m->who, sb->who ) == 0 )
205                                        {
206                                                sb->msgq = g_slist_append( sb->msgq, m );
207                                                md->msgq = g_slist_remove( md->msgq, m );
208                                        }
209                                }
210                        }
211                }
212                else
213                {
214                        imcb_error( ic, "Syntax error" );
215                        imc_logout( ic, TRUE );
216                        return( 0 );
217                }
218        }
219        else if( strcmp( cmd[0], "USR" ) == 0 )
220        {
221                if( num_parts == 5 && strcmp( cmd[2], "TWN" ) == 0 && strcmp( cmd[3], "S" ) == 0 )
222                {
223                        /* Time for some Passport black magic... */
224                        if( !passport_get_token( msn_auth_got_passport_token, ic, ic->acc->user, ic->acc->pass, cmd[4] ) )
225                        {
226                                imcb_error( ic, "Error while contacting Passport server" );
227                                imc_logout( ic, TRUE );
228                                return( 0 );
229                        }
230                }
231                else if( num_parts == 7 && strcmp( cmd[2], "OK" ) == 0 )
232                {
233                        set_t *s;
234                       
235                        http_decode( cmd[4] );
236                       
237                        strncpy( ic->displayname, cmd[4], sizeof( ic->displayname ) );
238                        ic->displayname[sizeof(ic->displayname)-1] = 0;
239                       
240                        if( ( s = set_find( &ic->acc->set, "display_name" ) ) )
241                        {
242                                g_free( s->value );
243                                s->value = g_strdup( cmd[4] );
244                        }
245                       
246                        imcb_log( ic, "Authenticated, getting buddy list" );
247                       
248                        g_snprintf( buf, sizeof( buf ), "SYN %d 0\r\n", ++md->trId );
249                        return( msn_write( ic, buf, strlen( buf ) ) );
250                }
251                else
252                {
253                        imcb_error( ic, "Unknown authentication type" );
254                        imc_logout( ic, FALSE );
255                        return( 0 );
256                }
257        }
258        else if( strcmp( cmd[0], "MSG" ) == 0 )
259        {
260                if( num_parts != 4 )
261                {
262                        imcb_error( ic, "Syntax error" );
263                        imc_logout( ic, TRUE );
264                        return( 0 );
265                }
266               
267                md->handler->msglen = atoi( cmd[3] );
268               
269                if( md->handler->msglen <= 0 )
270                {
271                        imcb_error( ic, "Syntax error" );
272                        imc_logout( ic, TRUE );
273                        return( 0 );
274                }
275        }
276        else if( strcmp( cmd[0], "SYN" ) == 0 )
277        {
278                if( num_parts == 5 )
279                {
280                        int i, groupcount;
281                       
282                        groupcount = atoi( cmd[4] );
283                        if( groupcount > 0 )
284                        {
285                                /* valgrind says this is leaking memory, I'm guessing
286                                   that this happens during server redirects. */
287                                if( md->grouplist )
288                                {
289                                        for( i = 0; i < md->groupcount; i ++ )
290                                                g_free( md->grouplist[i] );
291                                        g_free( md->grouplist );
292                                }
293                               
294                                md->groupcount = groupcount;
295                                md->grouplist = g_new0( char *, md->groupcount );
296                        }
297                       
298                        md->buddycount = atoi( cmd[3] );
299                        if( !*cmd[3] || md->buddycount == 0 )
300                                msn_logged_in( ic );
301                }
302                else
303                {
304                        /* Hrrm... This SYN reply doesn't really look like something we expected.
305                           Let's assume everything is okay. */
306                       
307                        msn_logged_in( ic );
308                }
309        }
310        else if( strcmp( cmd[0], "LST" ) == 0 )
311        {
312                int list;
313               
314                if( num_parts != 4 && num_parts != 5 )
315                {
316                        imcb_error( ic, "Syntax error" );
317                        imc_logout( ic, TRUE );
318                        return( 0 );
319                }
320               
321                http_decode( cmd[2] );
322                list = atoi( cmd[3] );
323               
324                if( list & 1 ) /* FL */
325                {
326                        char *group = NULL;
327                        int num;
328                       
329                        if( cmd[4] != NULL && sscanf( cmd[4], "%d", &num ) == 1 && num < md->groupcount )
330                                group = md->grouplist[num];
331                       
332                        imcb_add_buddy( ic, cmd[1], group );
333                        imcb_rename_buddy( ic, cmd[1], cmd[2] );
334                }
335                if( list & 2 ) /* AL */
336                {
337                        ic->permit = g_slist_append( ic->permit, g_strdup( cmd[1] ) );
338                }
339                if( list & 4 ) /* BL */
340                {
341                        ic->deny = g_slist_append( ic->deny, g_strdup( cmd[1] ) );
342                }
343                if( list & 8 ) /* RL */
344                {
345                        if( ( list & 6 ) == 0 )
346                                msn_buddy_ask( ic, cmd[1], cmd[2] );
347                }
348               
349                if( --md->buddycount == 0 )
350                {
351                        if( ic->flags & OPT_LOGGED_IN )
352                        {
353                                imcb_log( ic, "Successfully transferred to different server" );
354                                g_snprintf( buf, sizeof( buf ), "CHG %d %s %d\r\n", ++md->trId, md->away_state->code, 0 );
355                                return( msn_write( ic, buf, strlen( buf ) ) );
356                        }
357                        else
358                        {
359                                msn_logged_in( ic );
360                        }
361                }
362        }
363        else if( strcmp( cmd[0], "LSG" ) == 0 )
364        {
365                int num;
366               
367                if( num_parts != 4 )
368                {
369                        imcb_error( ic, "Syntax error" );
370                        imc_logout( ic, TRUE );
371                        return( 0 );
372                }
373               
374                http_decode( cmd[2] );
375                num = atoi( cmd[1] );
376               
377                if( num < md->groupcount )
378                        md->grouplist[num] = g_strdup( cmd[2] );
379        }
380        else if( strcmp( cmd[0], "CHL" ) == 0 )
381        {
382                md5_state_t state;
383                md5_byte_t digest[16];
384                int i;
385               
386                if( num_parts != 3 )
387                {
388                        imcb_error( ic, "Syntax error" );
389                        imc_logout( ic, TRUE );
390                        return( 0 );
391                }
392               
393                md5_init( &state );
394                md5_append( &state, (const md5_byte_t *) cmd[2], strlen( cmd[2] ) );
395                md5_append( &state, (const md5_byte_t *) QRY_CODE, strlen( QRY_CODE ) );
396                md5_finish( &state, digest );
397               
398                g_snprintf( buf, sizeof( buf ), "QRY %d %s %d\r\n", ++md->trId, QRY_NAME, 32 );
399                for( i = 0; i < 16; i ++ )
400                        g_snprintf( buf + strlen( buf ), 3, "%02x", digest[i] );
401               
402                return( msn_write( ic, buf, strlen( buf ) ) );
403        }
404        else if( strcmp( cmd[0], "ILN" ) == 0 )
405        {
406                const struct msn_away_state *st;
407               
408                if( num_parts != 6 )
409                {
410                        imcb_error( ic, "Syntax error" );
411                        imc_logout( ic, TRUE );
412                        return( 0 );
413                }
414               
415                http_decode( cmd[4] );
416                imcb_rename_buddy( ic, cmd[3], cmd[4] );
417               
418                st = msn_away_state_by_code( cmd[2] );
419                if( !st )
420                {
421                        /* FIXME: Warn/Bomb about unknown away state? */
422                        st = msn_away_state_list;
423                }
424               
425                imcb_buddy_status( ic, cmd[3], OPT_LOGGED_IN |
426                                   ( st->number ? OPT_AWAY : 0 ), st->name, NULL );
427        }
428        else if( strcmp( cmd[0], "FLN" ) == 0 )
429        {
430                if( cmd[1] )
431                        imcb_buddy_status( ic, cmd[1], 0, NULL, NULL );
432        }
433        else if( strcmp( cmd[0], "NLN" ) == 0 )
434        {
435                const struct msn_away_state *st;
436               
437                if( num_parts != 5 )
438                {
439                        imcb_error( ic, "Syntax error" );
440                        imc_logout( ic, TRUE );
441                        return( 0 );
442                }
443               
444                http_decode( cmd[3] );
445                imcb_rename_buddy( ic, cmd[2], cmd[3] );
446               
447                st = msn_away_state_by_code( cmd[1] );
448                if( !st )
449                {
450                        /* FIXME: Warn/Bomb about unknown away state? */
451                        st = msn_away_state_list;
452                }
453               
454                imcb_buddy_status( ic, cmd[2], OPT_LOGGED_IN |
455                                   ( st->number ? OPT_AWAY : 0 ), st->name, NULL );
456        }
457        else if( strcmp( cmd[0], "RNG" ) == 0 )
458        {
459                struct msn_switchboard *sb;
460                char *server;
461                int session, port;
462               
463                if( num_parts != 7 )
464                {
465                        imcb_error( ic, "Syntax error" );
466                        imc_logout( ic, TRUE );
467                        return( 0 );
468                }
469               
470                session = atoi( cmd[1] );
471               
472                server = strchr( cmd[2], ':' );
473                if( !server )
474                {
475                        imcb_error( ic, "Syntax error" );
476                        imc_logout( ic, TRUE );
477                        return( 0 );
478                }
479                *server = 0;
480                port = atoi( server + 1 );
481                server = cmd[2];
482               
483                if( strcmp( cmd[3], "CKI" ) != 0 )
484                {
485                        imcb_error( ic, "Unknown authentication method for switchboard" );
486                        imc_logout( ic, TRUE );
487                        return( 0 );
488                }
489               
490                debug( "Got a call from %s (session %d). Key = %s", cmd[5], session, cmd[4] );
491               
492                if( ( sb = msn_sb_create( ic, server, port, cmd[4], session ) ) == NULL )
493                {
494                        /* Although this isn't strictly fatal for the NS connection, it's
495                           definitely something serious (we ran out of file descriptors?). */
496                        imcb_error( ic, "Could not create new switchboard" );
497                        imc_logout( ic, TRUE );
498                        return( 0 );
499                }
500                else
501                {
502                        sb->who = g_strdup( cmd[5] );
503                }
504        }
505        else if( strcmp( cmd[0], "ADD" ) == 0 )
506        {
507                if( num_parts == 6 && strcmp( cmd[2], "RL" ) == 0 )
508                {
509                        GSList *l;
510                       
511                        http_decode( cmd[5] );
512                       
513                        if( strchr( cmd[4], '@' ) == NULL )
514                        {
515                                imcb_error( ic, "Syntax error" );
516                                imc_logout( ic, TRUE );
517                                return 0;
518                        }
519                       
520                        /* We got added by someone. If we don't have this
521                           person in permit/deny yet, inform the user. */
522                        for( l = ic->permit; l; l = l->next )
523                                if( g_strcasecmp( l->data, cmd[4] ) == 0 )
524                                        return 1;
525                       
526                        for( l = ic->deny; l; l = l->next )
527                                if( g_strcasecmp( l->data, cmd[4] ) == 0 )
528                                        return 1;
529                       
530                        msn_buddy_ask( ic, cmd[4], cmd[5] );
531                }
532                else if( num_parts >= 6 && strcmp( cmd[2], "FL" ) == 0 )
533                {
534                        http_decode( cmd[5] );
535                        imcb_add_buddy( ic, cmd[4], NULL );
536                        imcb_rename_buddy( ic, cmd[4], cmd[5] );
537                }
538        }
539        else if( strcmp( cmd[0], "OUT" ) == 0 )
540        {
541                int allow_reconnect = TRUE;
542               
543                if( cmd[1] && strcmp( cmd[1], "OTH" ) == 0 )
544                {
545                        imcb_error( ic, "Someone else logged in with your account" );
546                        allow_reconnect = FALSE;
547                }
548                else if( cmd[1] && strcmp( cmd[1], "SSD" ) == 0 )
549                {
550                        imcb_error( ic, "Terminating session because of server shutdown" );
551                }
552                else
553                {
554                        imcb_error( ic, "Session terminated by remote server (reason unknown)" );
555                }
556               
557                imc_logout( ic, allow_reconnect );
558                return( 0 );
559        }
560        else if( strcmp( cmd[0], "REA" ) == 0 )
561        {
562                if( num_parts != 5 )
563                {
564                        imcb_error( ic, "Syntax error" );
565                        imc_logout( ic, TRUE );
566                        return( 0 );
567                }
568               
569                if( g_strcasecmp( cmd[3], ic->acc->user ) == 0 )
570                {
571                        set_t *s;
572                       
573                        http_decode( cmd[4] );
574                        strncpy( ic->displayname, cmd[4], sizeof( ic->displayname ) );
575                        ic->displayname[sizeof(ic->displayname)-1] = 0;
576                       
577                        if( ( s = set_find( &ic->acc->set, "display_name" ) ) )
578                        {
579                                g_free( s->value );
580                                s->value = g_strdup( cmd[4] );
581                        }
582                }
583                else
584                {
585                        /* This is not supposed to happen, but let's handle it anyway... */
586                        http_decode( cmd[4] );
587                        imcb_rename_buddy( ic, cmd[3], cmd[4] );
588                }
589        }
590        else if( strcmp( cmd[0], "IPG" ) == 0 )
591        {
592                imcb_error( ic, "Received IPG command, we don't handle them yet." );
593               
594                md->handler->msglen = atoi( cmd[1] );
595               
596                if( md->handler->msglen <= 0 )
597                {
598                        imcb_error( ic, "Syntax error" );
599                        imc_logout( ic, TRUE );
600                        return( 0 );
601                }
602        }
603        else if( isdigit( cmd[0][0] ) )
604        {
605                int num = atoi( cmd[0] );
606                const struct msn_status_code *err = msn_status_by_number( num );
607               
608                imcb_error( ic, "Error reported by MSN server: %s", err->text );
609               
610                if( err->flags & STATUS_FATAL )
611                {
612                        imc_logout( ic, TRUE );
613                        return( 0 );
614                }
615        }
616        else
617        {
618                /* debug( "Received unknown command from main server: %s", cmd[0] ); */
619        }
620       
621        return( 1 );
622}
623
624static int msn_ns_message( gpointer data, char *msg, int msglen, char **cmd, int num_parts )
625{
626        struct im_connection *ic = data;
627        char *body;
628        int blen = 0;
629       
630        if( !num_parts )
631                return( 1 );
632       
633        if( ( body = strstr( msg, "\r\n\r\n" ) ) )
634        {
635                body += 4;
636                blen = msglen - ( body - msg );
637        }
638       
639        if( strcmp( cmd[0], "MSG" ) == 0 )
640        {
641                if( g_strcasecmp( cmd[1], "Hotmail" ) == 0 )
642                {
643                        char *ct = msn_findheader( msg, "Content-Type:", msglen );
644                       
645                        if( !ct )
646                                return( 1 );
647                       
648                        if( g_strncasecmp( ct, "application/x-msmsgssystemmessage", 33 ) == 0 )
649                        {
650                                char *mtype;
651                                char *arg1;
652                               
653                                if( !body )
654                                        return( 1 );
655                               
656                                mtype = msn_findheader( body, "Type:", blen );
657                                arg1 = msn_findheader( body, "Arg1:", blen );
658                               
659                                if( mtype && strcmp( mtype, "1" ) == 0 )
660                                {
661                                        if( arg1 )
662                                                imcb_log( ic, "The server is going down for maintenance in %s minutes.", arg1 );
663                                }
664                               
665                                if( arg1 ) g_free( arg1 );
666                                if( mtype ) g_free( mtype );
667                        }
668                        else if( g_strncasecmp( ct, "text/x-msmsgsprofile", 20 ) == 0 )
669                        {
670                                /* We don't care about this profile for now... */
671                        }
672                        else if( g_strncasecmp( ct, "text/x-msmsgsinitialemailnotification", 37 ) == 0 )
673                        {
674                                char *inbox = msn_findheader( body, "Inbox-Unread:", blen );
675                                char *folders = msn_findheader( body, "Folders-Unread:", blen );
676                               
677                                if( inbox && folders && set_getbool( &ic->acc->set, "mail_notifications" ) )
678                                {
679                                        imcb_log( ic, "INBOX contains %s new messages, plus %s messages in other folders.", inbox, folders );
680                                }
681                               
682                                g_free( inbox );
683                                g_free( folders );
684                        }
685                        else if( g_strncasecmp( ct, "text/x-msmsgsemailnotification", 30 ) == 0 )
686                        {
687                                char *from = msn_findheader( body, "From-Addr:", blen );
688                                char *fromname = msn_findheader( body, "From:", blen );
689                               
690                                if( from && fromname && set_getbool( &ic->acc->set, "mail_notifications" ) )
691                                {
692                                        imcb_log( ic, "Received an e-mail message from %s <%s>.", fromname, from );
693                                }
694                        }
695                        else if( g_strncasecmp( ct, "text/x-msmsgsactivemailnotification", 35 ) == 0 )
696                        {
697                                /* Sorry, but this one really is *USELESS* */
698                        }
699                        else
700                        {
701                                debug( "Can't handle %s packet from notification server", ct );
702                        }
703                       
704                        g_free( ct );
705                }
706        }
707       
708        return( 1 );
709}
710
711static void msn_auth_got_passport_token( struct msn_auth_data *mad )
712{
713        struct im_connection *ic = mad->data;
714        struct msn_data *md;
715       
716        /* Dead connection? */
717        if( g_slist_find( msn_connections, ic ) == NULL )
718                return;
719       
720        md = ic->proto_data;
721        if( mad->token )
722        {
723                char buf[1024];
724               
725                g_snprintf( buf, sizeof( buf ), "USR %d TWN S %s\r\n", ++md->trId, mad->token );
726                msn_write( ic, buf, strlen( buf ) );
727        }
728        else
729        {
730                imcb_error( ic, "Error during Passport authentication: %s", mad->error );
731                imc_logout( ic, TRUE );
732        }
733}
Note: See TracBrowser for help on using the repository browser.