Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • protocols/msn/ns.c

    r2fe8297 r5ebff60  
    3535static gboolean msn_ns_connected(gpointer data, gint source, b_input_condition cond);
    3636static gboolean msn_ns_callback(gpointer data, gint source, b_input_condition cond);
     37static int msn_ns_command(struct msn_handler_data *handler, char **cmd, int num_parts);
     38static int msn_ns_message(struct msn_handler_data *handler, char *msg, int msglen, char **cmd, int num_parts);
    3739
    3840static void msn_ns_send_adl_start(struct im_connection *ic);
    3941static void msn_ns_send_adl(struct im_connection *ic);
    40 static void msn_ns_structured_message(struct msn_data *md, char *msg, int msglen, char **cmd);
    41 static void msn_ns_sdg(struct msn_data *md, char *who, char **parts, char *action);
    42 static void msn_ns_nfy(struct msn_data *md, char *who, char **parts, char *action, gboolean is_put);
    4342
    4443int msn_ns_write(struct im_connection *ic, int fd, const char *fmt, ...)
     
    5554
    5655        if (fd < 0) {
    57                 fd = md->fd;
     56                fd = md->ns->fd;
    5857        }
    5958
    6059        if (getenv("BITLBEE_DEBUG")) {
    61                 fprintf(stderr, "\x1b[91m>>>[NS%d] %s\n\x1b[97m", fd, out);
     60                fprintf(stderr, "->NS%d:%s\n", fd, out);
    6261        }
    6362
    6463        len = strlen(out);
    65 
    66         if (md->is_http) {
    67                 st = len;
    68                 msn_gw_write(md->gw, out, len);
    69         } else {
    70                 st = write(fd, out, len);
    71         }
    72 
     64        st = write(fd, out, len);
    7365        g_free(out);
    7466        if (st != len) {
     
    8173}
    8274
    83 gboolean msn_ns_connect(struct im_connection *ic, const char *host, int port)
    84 {
    85         struct msn_data *md = ic->proto_data;
    86 
    87         if (md->fd >= 0) {
    88                 closesocket(md->fd);
    89         }
    90 
    91         if (md->is_http) {
    92                 md->gw = msn_gw_new(ic);
    93                 md->gw->callback = msn_ns_callback;
    94                 msn_ns_connected(md, -1, B_EV_IO_READ);
    95         } else {
    96                 md->fd = proxy_connect(host, port, msn_ns_connected, md);
    97                 if (md->fd < 0) {
    98                         imcb_error(ic, "Could not connect to server");
    99                         imc_logout(ic, TRUE);
    100                         return FALSE;
    101                 }
    102         }
    103 
    104         return TRUE;
    105 }
    106 
    107 static gboolean msn_ns_connected(gpointer data, gint source, b_input_condition cond)
    108 {
    109         struct msn_data *md = data;
    110         struct im_connection *ic = md->ic;
    111 
    112         if (source == -1 && !md->is_http) {
     75gboolean msn_ns_connect(struct im_connection *ic, struct msn_handler_data *handler, const char *host, int port)
     76{
     77        if (handler->fd >= 0) {
     78                closesocket(handler->fd);
     79        }
     80
     81        handler->exec_command = msn_ns_command;
     82        handler->exec_message = msn_ns_message;
     83        handler->data = ic;
     84        handler->fd = proxy_connect(host, port, msn_ns_connected, handler);
     85        if (handler->fd < 0) {
    11386                imcb_error(ic, "Could not connect to server");
    11487                imc_logout(ic, TRUE);
     
    11689        }
    11790
    118         g_free(md->rxq);
    119         md->rxlen = 0;
    120         md->rxq = g_new0(char, 1);
     91        return TRUE;
     92}
     93
     94static gboolean msn_ns_connected(gpointer data, gint source, b_input_condition cond)
     95{
     96        struct msn_handler_data *handler = data;
     97        struct im_connection *ic = handler->data;
     98        struct msn_data *md;
     99
     100        if (!g_slist_find(msn_connections, ic)) {
     101                return FALSE;
     102        }
     103
     104        md = ic->proto_data;
     105
     106        if (source == -1) {
     107                imcb_error(ic, "Could not connect to server");
     108                imc_logout(ic, TRUE);
     109                return FALSE;
     110        }
     111
     112        g_free(handler->rxq);
     113        handler->rxlen = 0;
     114        handler->rxq = g_new0(char, 1);
    121115
    122116        if (md->uuid == NULL) {
     
    136130
    137131        if (msn_ns_write(ic, source, "VER %d %s CVR0\r\n", ++md->trId, MSNP_VER)) {
    138                 if (!md->is_http) {
    139                         md->inpa = b_input_add(md->fd, B_EV_IO_READ, msn_ns_callback, md);
    140                 }
     132                handler->inpa = b_input_add(handler->fd, B_EV_IO_READ, msn_ns_callback, handler);
    141133                imcb_log(ic, "Connected to server, waiting for reply");
    142134        }
     
    145137}
    146138
    147 void msn_ns_close(struct msn_data *md)
    148 {
    149         if (md->gw) {
    150                 msn_gw_free(md->gw);
    151         }
    152         if (md->fd >= 0) {
    153                 closesocket(md->fd);
    154                 b_event_remove(md->inpa);
    155         }
    156 
    157         md->fd = md->inpa = -1;
    158         g_free(md->rxq);
    159         g_free(md->cmd_text);
    160 
    161         md->rxlen = 0;
    162         md->rxq = NULL;
    163         md->cmd_text = NULL;
     139void msn_ns_close(struct msn_handler_data *handler)
     140{
     141        if (handler->fd >= 0) {
     142                closesocket(handler->fd);
     143                b_event_remove(handler->inpa);
     144        }
     145
     146        handler->fd = handler->inpa = -1;
     147        g_free(handler->rxq);
     148        g_free(handler->cmd_text);
     149
     150        handler->rxlen = 0;
     151        handler->rxq = NULL;
     152        handler->cmd_text = NULL;
    164153}
    165154
    166155static gboolean msn_ns_callback(gpointer data, gint source, b_input_condition cond)
    167156{
    168         struct msn_data *md = data;
    169         struct im_connection *ic = md->ic;
    170         char *bytes;
    171         int st;
    172 
    173         if (md->is_http) {
    174                 st = msn_gw_read(md->gw, &bytes);
    175         } else {
    176                 bytes = g_malloc(1024);
    177                 st = read(md->fd, bytes, 1024);
    178         }
    179 
    180         if (st <= 0) {
     157        struct msn_handler_data *handler = data;
     158        struct im_connection *ic = handler->data;
     159
     160        if (msn_handler(handler) == -1) {  /* Don't do this on ret == 0, it's already done then. */
    181161                imcb_error(ic, "Error while reading from server");
    182162                imc_logout(ic, TRUE);
     163
    183164                return FALSE;
    184         }
    185 
    186         msn_queue_feed(md, bytes, st);
    187 
    188         g_free(bytes);
    189 
    190         /* Ignore ret == 0, it's already disconnected then. */
    191         msn_handler(md);
    192 
    193         return TRUE;
    194        
    195 }
    196 
    197 int msn_ns_command(struct msn_data *md, char **cmd, int num_parts)
    198 {
    199         struct im_connection *ic = md->ic;
     165        } else {
     166                return TRUE;
     167        }
     168}
     169
     170static int msn_ns_command(struct msn_handler_data *handler, char **cmd, int num_parts)
     171{
     172        struct im_connection *ic = handler->data;
     173        struct msn_data *md = ic->proto_data;
    200174
    201175        if (num_parts == 0) {
     
    211185                }
    212186
    213                 return(msn_ns_write(ic, md->fd, "CVR %d 0x0409 mac 10.2.0 ppc macmsgs 3.5.1 macmsgs %s VmVyc2lvbjogMQ0KWGZyQ291bnQ6IDINClhmclNlbnRVVENUaW1lOiA2MzU2MTQ3OTU5NzgzOTAwMDANCklzR2VvWGZyOiB0cnVlDQo=\r\n",
     187                return(msn_ns_write(ic, handler->fd, "CVR %d 0x0409 mac 10.2.0 ppc macmsgs 3.5.1 macmsgs %s\r\n",
    214188                                    ++md->trId, ic->acc->user));
    215189        } else if (strcmp(cmd[0], "CVR") == 0) {
    216190                /* We don't give a damn about the information we just received */
    217                 return msn_ns_write(ic, md->fd, "USR %d SSO I %s\r\n", ++md->trId, ic->acc->user);
     191                return msn_ns_write(ic, handler->fd, "USR %d SSO I %s\r\n", ++md->trId, ic->acc->user);
    218192        } else if (strcmp(cmd[0], "XFR") == 0) {
    219193                char *server;
     
    221195
    222196                if (num_parts >= 6 && strcmp(cmd[2], "NS") == 0) {
    223                         b_event_remove(md->inpa);
    224                         md->inpa = -1;
     197                        b_event_remove(handler->inpa);
     198                        handler->inpa = -1;
    225199
    226200                        server = strchr(cmd[3], ':');
     
    235209
    236210                        imcb_log(ic, "Transferring to other server");
    237                         return msn_ns_connect(ic, server, port);
     211                        return msn_ns_connect(ic, handler, server, port);
     212                } else if (num_parts >= 6 && strcmp(cmd[2], "SB") == 0) {
     213                        struct msn_switchboard *sb;
     214
     215                        server = strchr(cmd[3], ':');
     216                        if (!server) {
     217                                imcb_error(ic, "Syntax error");
     218                                imc_logout(ic, TRUE);
     219                                return(0);
     220                        }
     221                        *server = 0;
     222                        port = atoi(server + 1);
     223                        server = cmd[3];
     224
     225                        if (strcmp(cmd[4], "CKI") != 0) {
     226                                imcb_error(ic, "Unknown authentication method for switchboard");
     227                                imc_logout(ic, TRUE);
     228                                return(0);
     229                        }
     230
     231                        debug("Connecting to a new switchboard with key %s", cmd[5]);
     232
     233                        if ((sb = msn_sb_create(ic, server, port, cmd[5], MSN_SB_NEW)) == NULL) {
     234                                /* Although this isn't strictly fatal for the NS connection, it's
     235                                   definitely something serious (we ran out of file descriptors?). */
     236                                imcb_error(ic, "Could not create new switchboard");
     237                                imc_logout(ic, TRUE);
     238                                return(0);
     239                        }
     240
     241                        if (md->msgq) {
     242                                struct msn_message *m = md->msgq->data;
     243                                GSList *l;
     244
     245                                sb->who = g_strdup(m->who);
     246
     247                                /* Move all the messages to the first user in the message
     248                                   queue to the switchboard message queue. */
     249                                l = md->msgq;
     250                                while (l) {
     251                                        m = l->data;
     252                                        l = l->next;
     253                                        if (strcmp(m->who, sb->who) == 0) {
     254                                                sb->msgq = g_slist_append(sb->msgq, m);
     255                                                md->msgq = g_slist_remove(md->msgq, m);
     256                                        }
     257                                }
     258                        }
    238259                } else {
    239260                        imcb_error(ic, "Syntax error");
     
    269290                }
    270291
    271                 md->msglen = atoi(cmd[3]);
    272 
    273                 if (md->msglen <= 0) {
     292                handler->msglen = atoi(cmd[3]);
     293
     294                if (handler->msglen <= 0) {
    274295                        imcb_error(ic, "Syntax error");
    275296                        imc_logout(ic, TRUE);
    276297                        return(0);
    277298                }
     299        } else if (strcmp(cmd[0], "BLP") == 0) {
     300                msn_ns_send_adl_start(ic);
     301                return msn_ns_finish_login(ic);
    278302        } else if (strcmp(cmd[0], "ADL") == 0) {
    279303                if (num_parts >= 3 && strcmp(cmd[2], "OK") == 0) {
     
    281305                        return msn_ns_finish_login(ic);
    282306                } else if (num_parts >= 3) {
    283                         md->msglen = atoi(cmd[2]);
    284                 }
     307                        handler->msglen = atoi(cmd[2]);
     308                }
     309        } else if (strcmp(cmd[0], "PRP") == 0) {
     310                imcb_connected(ic);
    285311        } else if (strcmp(cmd[0], "CHL") == 0) {
    286312                char *resp;
     
    300326                g_free(resp);
    301327                return st;
    302         } else if (strcmp(cmd[0], "QRY") == 0) {
    303                 /* CONGRATULATIONS */
     328        } else if (strcmp(cmd[0], "ILN") == 0 || strcmp(cmd[0], "NLN") == 0) {
     329                const struct msn_away_state *st;
     330                const char *handle;
     331                int cap = 0;
     332
     333                if (num_parts < 6) {
     334                        imcb_error(ic, "Syntax error");
     335                        imc_logout(ic, TRUE);
     336                        return(0);
     337                }
     338                /* ILN and NLN are more or less the same, except ILN has a trId
     339                   at the start, and NLN has a capability field at the end.
     340                   Does ILN still exist BTW? */
     341                if (cmd[0][1] == 'I') {
     342                        cmd++;
     343                } else {
     344                        cap = atoi(cmd[4]);
     345                }
     346
     347                handle = msn_normalize_handle(cmd[2]);
     348                if (strcmp(handle, ic->acc->user) == 0) {
     349                        return 1; /* That's me! */
     350
     351                }
     352                http_decode(cmd[3]);
     353                imcb_rename_buddy(ic, handle, cmd[3]);
     354
     355                st = msn_away_state_by_code(cmd[1]);
     356                if (!st) {
     357                        /* FIXME: Warn/Bomb about unknown away state? */
     358                        st = msn_away_state_list + 1;
     359                }
     360
     361                imcb_buddy_status(ic, handle, OPT_LOGGED_IN |
     362                                  (st != msn_away_state_list ? OPT_AWAY : 0) |
     363                                  (cap & 1 ? OPT_MOBILE : 0),
     364                                  st->name, NULL);
     365
     366                msn_sb_stop_keepalives(msn_sb_by_handle(ic, handle));
     367        } else if (strcmp(cmd[0], "FLN") == 0) {
     368                const char *handle;
     369
     370                if (cmd[1] == NULL) {
     371                        return 1;
     372                }
     373
     374                handle = msn_normalize_handle(cmd[1]);
     375                imcb_buddy_status(ic, handle, 0, NULL, NULL);
     376                msn_sb_start_keepalives(msn_sb_by_handle(ic, handle), TRUE);
     377        } else if (strcmp(cmd[0], "RNG") == 0) {
     378                struct msn_switchboard *sb;
     379                char *server;
     380                int session, port;
     381
     382                if (num_parts < 7) {
     383                        imcb_error(ic, "Syntax error");
     384                        imc_logout(ic, TRUE);
     385                        return(0);
     386                }
     387
     388                session = atoi(cmd[1]);
     389
     390                server = strchr(cmd[2], ':');
     391                if (!server) {
     392                        imcb_error(ic, "Syntax error");
     393                        imc_logout(ic, TRUE);
     394                        return(0);
     395                }
     396                *server = 0;
     397                port = atoi(server + 1);
     398                server = cmd[2];
     399
     400                if (strcmp(cmd[3], "CKI") != 0) {
     401                        imcb_error(ic, "Unknown authentication method for switchboard");
     402                        imc_logout(ic, TRUE);
     403                        return(0);
     404                }
     405
     406                debug("Got a call from %s (session %d). Key = %s", cmd[5], session, cmd[4]);
     407
     408                if ((sb = msn_sb_create(ic, server, port, cmd[4], session)) == NULL) {
     409                        /* Although this isn't strictly fatal for the NS connection, it's
     410                           definitely something serious (we ran out of file descriptors?). */
     411                        imcb_error(ic, "Could not create new switchboard");
     412                        imc_logout(ic, TRUE);
     413                        return(0);
     414                } else {
     415                        sb->who = g_strdup(msn_normalize_handle(cmd[5]));
     416                }
    304417        } else if (strcmp(cmd[0], "OUT") == 0) {
    305                 imcb_error(ic, "Session terminated by remote server (%s)", cmd[1] ? cmd[1] : "reason unknown");
    306                 imc_logout(ic, TRUE);
     418                int allow_reconnect = TRUE;
     419
     420                if (cmd[1] && strcmp(cmd[1], "OTH") == 0) {
     421                        imcb_error(ic, "Someone else logged in with your account");
     422                        allow_reconnect = FALSE;
     423                } else if (cmd[1] && strcmp(cmd[1], "SSD") == 0) {
     424                        imcb_error(ic, "Terminating session because of server shutdown");
     425                } else {
     426                        imcb_error(ic, "Session terminated by remote server (%s)",
     427                                   cmd[1] ? cmd[1] : "reason unknown)");
     428                }
     429
     430                imc_logout(ic, allow_reconnect);
    307431                return(0);
    308         } else if (strcmp(cmd[0], "GCF") == 0) {
     432        } else if (strcmp(cmd[0], "IPG") == 0) {
     433                imcb_error(ic, "Received IPG command, we don't handle them yet.");
     434
     435                handler->msglen = atoi(cmd[1]);
     436
     437                if (handler->msglen <= 0) {
     438                        imcb_error(ic, "Syntax error");
     439                        imc_logout(ic, TRUE);
     440                        return(0);
     441                }
     442        }
     443#if 0
     444        else if (strcmp(cmd[0], "ADG") == 0) {
     445                char *group = g_strdup(cmd[3]);
     446                int groupnum, i;
     447                GSList *l, *next;
     448
     449                http_decode(group);
     450                if (sscanf(cmd[4], "%d", &groupnum) == 1) {
     451                        if (groupnum >= md->groupcount) {
     452                                md->grouplist = g_renew(char *, md->grouplist, groupnum + 1);
     453                                for (i = md->groupcount; i <= groupnum; i++) {
     454                                        md->grouplist[i] = NULL;
     455                                }
     456                                md->groupcount = groupnum + 1;
     457                        }
     458                        g_free(md->grouplist[groupnum]);
     459                        md->grouplist[groupnum] = group;
     460                } else {
     461                        /* Shouldn't happen, but if it does, give up on the group. */
     462                        g_free(group);
     463                        imcb_error(ic, "Syntax error");
     464                        imc_logout(ic, TRUE);
     465                        return 0;
     466                }
     467
     468                for (l = md->grpq; l; l = next) {
     469                        struct msn_groupadd *ga = l->data;
     470                        next = l->next;
     471                        if (g_strcasecmp(ga->group, group) == 0) {
     472                                if (!msn_buddy_list_add(ic, "FL", ga->who, ga->who, group)) {
     473                                        return 0;
     474                                }
     475
     476                                g_free(ga->group);
     477                                g_free(ga->who);
     478                                g_free(ga);
     479                                md->grpq = g_slist_remove(md->grpq, ga);
     480                        }
     481                }
     482        }
     483#endif
     484        else if (strcmp(cmd[0], "GCF") == 0) {
    309485                /* Coming up is cmd[2] bytes of stuff we're supposed to
    310486                   censore. Meh. */
    311                 md->msglen = atoi(cmd[2]);
    312         } else if ((strcmp(cmd[0], "NFY") == 0) || (strcmp(cmd[0], "SDG") == 0)) {
     487                handler->msglen = atoi(cmd[2]);
     488        } else if (strcmp(cmd[0], "UBX") == 0) {
     489                /* Status message. */
    313490                if (num_parts >= 3) {
    314                         md->msglen = atoi(cmd[2]);
    315                 }
    316         } else if (strcmp(cmd[0], "PUT") == 0) {
    317                 if (num_parts >= 4) {
    318                         md->msglen = atoi(cmd[3]);
     491                        handler->msglen = atoi(cmd[2]);
    319492                }
    320493        } else if (strcmp(cmd[0], "NOT") == 0) {
     494                /* Some kind of notification, poorly documented but
     495                   apparently used to announce address book changes. */
    321496                if (num_parts >= 2) {
    322                         md->msglen = atoi(cmd[1]);
     497                        handler->msglen = atoi(cmd[1]);
     498                }
     499        } else if (strcmp(cmd[0], "UBM") == 0) {
     500                if (num_parts >= 7) {
     501                        handler->msglen = atoi(cmd[6]);
    323502                }
    324503        } else if (strcmp(cmd[0], "QNG") == 0) {
     
    337516                /* Oh yes, errors can have payloads too now. Discard them for now. */
    338517                if (num_parts >= 3) {
    339                         md->msglen = atoi(cmd[2]);
     518                        handler->msglen = atoi(cmd[2]);
    340519                }
    341520        } else {
    342                 imcb_error(ic, "Received unknown command from main server: %s", cmd[0]);
     521                /* debug( "Received unknown command from main server: %s", cmd[0] ); */
    343522        }
    344523
     
    346525}
    347526
    348 int msn_ns_message(struct msn_data *md, char *msg, int msglen, char **cmd, int num_parts)
    349 {
    350         struct im_connection *ic = md->ic;
     527static int msn_ns_message(struct msn_handler_data *handler, char *msg, int msglen, char **cmd, int num_parts)
     528{
     529        struct im_connection *ic = handler->data;
    351530        char *body;
    352531        int blen = 0;
     
    419598                                }
    420599                        } else if (g_strncasecmp(ct, "text/x-msmsgsactivemailnotification", 35) == 0) {
    421                                 /* Notification that a message has been read... Ignore it */
     600                        } else if (g_strncasecmp(ct, "text/x-msmsgsinitialmdatanotification", 37) == 0 ||
     601                                   g_strncasecmp(ct, "text/x-msmsgsoimnotification", 28) == 0) {
     602                                /* We received an offline message. Or at least notification
     603                                   that there is one waiting for us. Fetching the message(s)
     604                                   and purging them from the server is a lot of SOAPy work
     605                                   not worth doing IMHO. Also I thought it was possible to
     606                                   have the notification server send them directly, I was
     607                                   pretty sure I saw Pidgin do it..
     608
     609                                   At least give a notification for now, seems like a
     610                                   reasonable thing to do. Only problem is, they'll keep
     611                                   coming back at login time until you read them using a
     612                                   different client. :-( */
     613
     614                                char *xml = get_rfc822_header(body, "Mail-Data:", blen);
     615                                struct xt_node *md, *m;
     616
     617                                if (!xml) {
     618                                        return 1;
     619                                }
     620                                md = xt_from_string(xml, 0);
     621                                if (!md) {
     622                                        return 1;
     623                                }
     624
     625                                for (m = md->children; (m = xt_find_node(m, "M")); m = m->next) {
     626                                        struct xt_node *e = xt_find_node(m->children, "E");
     627                                        struct xt_node *rt = xt_find_node(m->children, "RT");
     628                                        struct tm tp;
     629                                        time_t msgtime = 0;
     630
     631                                        if (!e || !e->text) {
     632                                                continue;
     633                                        }
     634
     635                                        memset(&tp, 0, sizeof(tp));
     636                                        if (rt && rt->text &&
     637                                            sscanf(rt->text, "%4d-%2d-%2dT%2d:%2d:%2d.",
     638                                                   &tp.tm_year, &tp.tm_mon, &tp.tm_mday,
     639                                                   &tp.tm_hour, &tp.tm_min, &tp.tm_sec) == 6) {
     640                                                tp.tm_year -= 1900;
     641                                                tp.tm_mon--;
     642                                                msgtime = mktime_utc(&tp);
     643
     644                                        }
     645                                        imcb_buddy_msg(ic, e->text,
     646                                                       "<< \002BitlBee\002 - Received offline message. BitlBee can't show these. >>", 0,
     647                                                       msgtime);
     648                                }
     649
     650                                g_free(xml);
     651                                xt_free_node(md);
    422652                        } else {
    423653                                debug("Can't handle %s packet from notification server", ct);
     
    426656                        g_free(ct);
    427657                }
     658        } else if (strcmp(cmd[0], "UBX") == 0) {
     659                struct xt_node *ubx, *psm;
     660                char *psm_text = NULL;
     661
     662                ubx = xt_from_string(msg, msglen);
     663                if (ubx && strcmp(ubx->name, "Data") == 0 &&
     664                    (psm = xt_find_node(ubx->children, "PSM"))) {
     665                        psm_text = psm->text;
     666                }
     667
     668                imcb_buddy_status_msg(ic, msn_normalize_handle(cmd[1]), psm_text);
     669                xt_free_node(ubx);
    428670        } else if (strcmp(cmd[0], "ADL") == 0) {
    429671                struct xt_node *adl, *d, *c;
     
    474716                        }
    475717                }
    476         } else if ((strcmp(cmd[0], "SDG") == 0) || (strcmp(cmd[0], "NFY") == 0)) {
    477                 msn_ns_structured_message(md, msg, msglen, cmd);
     718        } else if (strcmp(cmd[0], "UBM") == 0) {
     719                /* This one will give us msgs from federated networks. Technically
     720                   it should also get us offline messages, but I don't know how
     721                   I can signal MSN servers to use it. */
     722                char *ct, *handle;
     723
     724                if (strcmp(cmd[1], ic->acc->user) == 0) {
     725                        /* With MPOP, you'll get copies of your own msgs from other
     726                           sessions. Discard those at least for now. */
     727                        return 1;
     728                }
     729
     730                ct = get_rfc822_header(msg, "Content-Type", msglen);
     731                if (strncmp(ct, "text/plain", 10) != 0) {
     732                        /* Typing notification or something? */
     733                        g_free(ct);
     734                        return 1;
     735                }
     736                if (strcmp(cmd[2], "1") != 0) {
     737                        handle = g_strdup_printf("%s:%s", cmd[2], cmd[1]);
     738                } else {
     739                        handle = g_strdup(cmd[1]);
     740                }
     741
     742                imcb_buddy_msg(ic, handle, body, 0, 0);
     743                g_free(handle);
    478744        }
    479745
    480746        return 1;
    481 }
    482 
    483 static void msn_ns_structured_message(struct msn_data *md, char *msg, int msglen, char **cmd)
    484 {
    485         char **parts = NULL;
    486         char *semicolon = NULL;
    487         char *action = NULL;
    488         char *from = NULL;
    489         char *who = NULL;
    490 
    491         parts = g_strsplit(msg, "\r\n\r\n", 4);
    492 
    493         if (!(from = get_rfc822_header(parts[0], "From", 0))) {
    494                 goto cleanup;
    495         }
    496 
    497         /* either the semicolon or the end of the string */
    498         semicolon = strchr(from, ';') ? : (from + strlen(from));
    499 
    500         who = g_strndup(from + 2, semicolon - from - 2);
    501 
    502         if ((strcmp(cmd[0], "SDG") == 0) && (action = get_rfc822_header(parts[2], "Message-Type", 0))) {
    503                 msn_ns_sdg(md, who, parts, action);
    504 
    505         } else if ((strcmp(cmd[0], "NFY") == 0) && (action = get_rfc822_header(parts[2], "Uri", 0))) {
    506                 gboolean is_put = (strcmp(cmd[1], "PUT") == 0);
    507                 msn_ns_nfy(md, who, parts, action, is_put);
    508         }
    509 
    510 cleanup:
    511         g_strfreev(parts);
    512         g_free(action);
    513         g_free(from);
    514         g_free(who);
    515 }
    516 
    517 static void msn_ns_sdg(struct msn_data *md, char *who, char **parts, char *action)
    518 {
    519         struct im_connection *ic = md->ic;
    520 
    521         if (strcmp(action, "Control/Typing") == 0) {
    522                 imcb_buddy_typing(ic, who, OPT_TYPING);
    523         } else if (strcmp(action, "Text") == 0) {
    524                 imcb_buddy_msg(ic, who, parts[3], 0, 0);
    525         }
    526 }
    527 
    528 static void msn_ns_nfy(struct msn_data *md, char *who, char **parts, char *action, gboolean is_put)
    529 {
    530         struct im_connection *ic = md->ic;
    531         struct xt_node *body = NULL;
    532         struct xt_node *s = NULL;
    533         const char *state = NULL;
    534         char *nick = NULL;
    535         char *psm = NULL;
    536         int flags = OPT_LOGGED_IN;
    537 
    538         if (strcmp(action, "/user") != 0) {
    539                 return;
    540         }
    541 
    542         if (!(body = xt_from_string(parts[3], 0))) {
    543                 goto cleanup;
    544         }
    545 
    546         s = body->children;
    547         while ((s = xt_find_node(s, "s"))) {
    548                 struct xt_node *s2;
    549                 char *n = xt_find_attr(s, "n");  /* service name: IM, PE, etc */
    550 
    551                 if (strcmp(n, "IM") == 0) {
    552                         /* IM has basic presence information */
    553                         if (!is_put) {
    554                                 /* NFY DEL with a <s> usually means log out from the last endpoint */
    555                                 flags &= ~OPT_LOGGED_IN;
    556                                 break;
    557                         }
    558 
    559                         s2 = xt_find_node(s->children, "Status");
    560                         if (s2 && s2->text_len) {
    561                                 const struct msn_away_state *msn_state = msn_away_state_by_code(s2->text);
    562                                 state = msn_state->name;
    563                                 if (msn_state != msn_away_state_list) {
    564                                         flags |= OPT_AWAY;
    565                                 }
    566                         }
    567                 } else if (strcmp(n, "PE") == 0) {
    568                         if ((s2 = xt_find_node(s->children, "PSM")) && s2->text_len) {
    569                                 psm = s2->text;
    570                         }
    571                         if ((s2 = xt_find_node(s->children, "FriendlyName")) && s2->text_len) {
    572                                 nick = s2->text;
    573                         }
    574                 }
    575                 s = s->next;
    576         }
    577 
    578         imcb_buddy_status(ic, who, flags, state, psm);
    579 
    580         if (nick) {
    581                 imcb_rename_buddy(ic, who, nick);
    582         }
    583 
    584 cleanup:
    585         xt_free_node(body);
    586747}
    587748
     
    607768void msn_auth_got_contact_list(struct im_connection *ic)
    608769{
     770        struct msn_data *md;
     771
    609772        /* Dead connection? */
    610773        if (g_slist_find(msn_connections, ic) == NULL) {
     
    612775        }
    613776
    614         msn_ns_send_adl_start(ic);
    615         msn_ns_finish_login(ic);
     777        md = ic->proto_data;
     778        msn_ns_write(ic, -1, "BLP %d %s\r\n", ++md->trId, "BL");
    616779}
    617780
    618781static gboolean msn_ns_send_adl_1(gpointer key, gpointer value, gpointer data)
    619782{
    620         struct xt_node *adl = data, *d, *c, *s;
     783        struct xt_node *adl = data, *d, *c;
    621784        struct bee_user *bu = value;
    622785        struct msn_buddy_data *bd = bu->data;
     
    647810        c = xt_new_node("c", NULL, NULL);
    648811        xt_add_attr(c, "n", handle);
     812        xt_add_attr(c, "l", l);
    649813        xt_add_attr(c, "t", "1");   /* FIXME: Network type, i.e. 32 for Y!MSG */
    650         s = xt_new_node("s", NULL, NULL);
    651         xt_add_attr(s, "n", "IM");
    652         xt_add_attr(s, "l", l);
    653         xt_insert_child(c, s);
    654814        xt_insert_child(d, c);
    655815
     
    721881
    722882        if ((md->flags & MSN_DONE_ADL) && (md->flags & MSN_GOT_PROFILE)) {
    723                 imcb_connected(ic);
     883                if (md->flags & MSN_EMAIL_UNVERIFIED) {
     884                        imcb_connected(ic);
     885                } else {
     886                        return msn_ns_set_display_name(ic, set_getstr(&ic->acc->set, "display_name"));
     887                }
    724888        }
    725889
     
    727891}
    728892
    729 // TODO: typing notifications, nudges lol, etc
    730893int msn_ns_sendmessage(struct im_connection *ic, bee_user_t *bu, const char *text)
    731894{
    732895        struct msn_data *md = ic->proto_data;
    733         int retval = 0;
    734         char *buf;
     896        int type = 0;
     897        char *buf, *handle;
    735898
    736899        if (strncmp(text, "\r\r\r", 3) == 0) {
     
    740903        }
    741904
    742         buf = g_strdup_printf(MSN_MESSAGE_HEADERS, bu->handle, ic->acc->user, md->uuid, strlen(text), text);
    743         retval = msn_ns_write(ic, -1, "SDG %d %zd\r\n%s", ++md->trId, strlen(buf), buf);
    744         g_free(buf);
    745         return retval;
    746 }
     905        /* This might be a federated contact. Get its network number,
     906           prefixed to bu->handle with a colon. Default is 1. */
     907        for (handle = bu->handle; g_ascii_isdigit(*handle); handle++) {
     908                type = type * 10 + *handle - '0';
     909        }
     910        if (*handle == ':') {
     911                handle++;
     912        } else {
     913                type = 1;
     914        }
     915
     916        buf = g_strdup_printf("%s%s", MSN_MESSAGE_HEADERS, text);
     917
     918        if (msn_ns_write(ic, -1, "UUM %d %s %d %d %zd\r\n%s",
     919                         ++md->trId, handle, type,
     920                         1,          /* type == IM (not nudge/typing) */
     921                         strlen(buf), buf)) {
     922                return 1;
     923        } else {
     924                return 0;
     925        }
     926}
     927
     928void msn_ns_oim_send_queue(struct im_connection *ic, GSList **msgq)
     929{
     930        GSList *l;
     931
     932        for (l = *msgq; l; l = l->next) {
     933                struct msn_message *m = l->data;
     934                bee_user_t *bu = bee_user_by_handle(ic->bee, ic, m->who);
     935
     936                if (bu) {
     937                        if (!msn_ns_sendmessage(ic, bu, m->text)) {
     938                                return;
     939                        }
     940                }
     941        }
     942
     943        while (*msgq != NULL) {
     944                struct msn_message *m = (*msgq)->data;
     945
     946                g_free(m->who);
     947                g_free(m->text);
     948                g_free(m);
     949
     950                *msgq = g_slist_remove(*msgq, m);
     951        }
     952}
Note: See TracChangeset for help on using the changeset viewer.