Changeset b1dc403 for protocols/msn/ns.c


Ignore:
Timestamp:
2015-05-04T21:58:50Z (9 years ago)
Author:
Wilmer van der Gaast <wilmer@…>
Children:
5726a0d
Parents:
531eabd (diff), 5ca1416 (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent.
Message:

Catch up with master.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • protocols/msn/ns.c

    r531eabd rb1dc403  
    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);
    37 static int msn_ns_command(struct msn_handler_data *handler, char **cmd, int num_parts);
    38 static int msn_ns_message(struct msn_handler_data *handler, char *msg, int msglen, char **cmd, int num_parts);
    3937
    4038static void msn_ns_send_adl_start(struct im_connection *ic);
    4139static void msn_ns_send_adl(struct im_connection *ic);
     40static void msn_ns_structured_message(struct msn_data *md, char *msg, int msglen, char **cmd);
     41static void msn_ns_sdg(struct msn_data *md, char *who, char **parts, char *action);
     42static void msn_ns_nfy(struct msn_data *md, char *who, char **parts, char *action, gboolean is_put);
    4243
    4344int msn_ns_write(struct im_connection *ic, int fd, const char *fmt, ...)
     
    5455
    5556        if (fd < 0) {
    56                 fd = md->ns->fd;
     57                fd = md->fd;
    5758        }
    5859
    5960        if (getenv("BITLBEE_DEBUG")) {
    60                 fprintf(stderr, "->NS%d:%s\n", fd, out);
     61                fprintf(stderr, "\x1b[91m>>>[NS%d] %s\n\x1b[97m", fd, out);
    6162        }
    6263
    6364        len = strlen(out);
    64         st = write(fd, out, len);
     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
    6573        g_free(out);
    6674        if (st != len) {
     
    7381}
    7482
    75 gboolean 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) {
     83gboolean 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
     107static 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) {
    86113                imcb_error(ic, "Could not connect to server");
    87114                imc_logout(ic, TRUE);
     
    89116        }
    90117
    91         return TRUE;
    92 }
    93 
    94 static 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);
     118        g_free(md->rxq);
     119        md->rxlen = 0;
     120        md->rxq = g_new0(char, 1);
    115121
    116122        if (md->uuid == NULL) {
     
    130136
    131137        if (msn_ns_write(ic, source, "VER %d %s CVR0\r\n", ++md->trId, MSNP_VER)) {
    132                 handler->inpa = b_input_add(handler->fd, B_EV_IO_READ, msn_ns_callback, handler);
     138                if (!md->is_http) {
     139                        md->inpa = b_input_add(md->fd, B_EV_IO_READ, msn_ns_callback, md);
     140                }
    133141                imcb_log(ic, "Connected to server, waiting for reply");
    134142        }
     
    137145}
    138146
    139 void 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;
     147void 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;
    153164}
    154165
    155166static gboolean msn_ns_callback(gpointer data, gint source, b_input_condition cond)
    156167{
    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. */
     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) {
    161181                imcb_error(ic, "Error while reading from server");
    162182                imc_logout(ic, TRUE);
    163 
    164183                return FALSE;
    165         } else {
    166                 return TRUE;
    167         }
    168 }
    169 
    170 static 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;
     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
     197int msn_ns_command(struct msn_data *md, char **cmd, int num_parts)
     198{
     199        struct im_connection *ic = md->ic;
    174200
    175201        if (num_parts == 0) {
     
    185211                }
    186212
    187                 return(msn_ns_write(ic, handler->fd, "CVR %d 0x0409 mac 10.2.0 ppc macmsgs 3.5.1 macmsgs %s\r\n",
     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",
    188214                                    ++md->trId, ic->acc->user));
    189215        } else if (strcmp(cmd[0], "CVR") == 0) {
    190216                /* We don't give a damn about the information we just received */
    191                 return msn_ns_write(ic, handler->fd, "USR %d SSO I %s\r\n", ++md->trId, ic->acc->user);
     217                return msn_ns_write(ic, md->fd, "USR %d SSO I %s\r\n", ++md->trId, ic->acc->user);
    192218        } else if (strcmp(cmd[0], "XFR") == 0) {
    193219                char *server;
     
    195221
    196222                if (num_parts >= 6 && strcmp(cmd[2], "NS") == 0) {
    197                         b_event_remove(handler->inpa);
    198                         handler->inpa = -1;
     223                        b_event_remove(md->inpa);
     224                        md->inpa = -1;
    199225
    200226                        server = strchr(cmd[3], ':');
     
    209235
    210236                        imcb_log(ic, "Transferring to other server");
    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                         }
     237                        return msn_ns_connect(ic, server, port);
    259238                } else {
    260239                        imcb_error(ic, "Syntax error");
     
    290269                }
    291270
    292                 handler->msglen = atoi(cmd[3]);
    293 
    294                 if (handler->msglen <= 0) {
     271                md->msglen = atoi(cmd[3]);
     272
     273                if (md->msglen <= 0) {
    295274                        imcb_error(ic, "Syntax error");
    296275                        imc_logout(ic, TRUE);
    297276                        return(0);
    298277                }
    299         } else if (strcmp(cmd[0], "BLP") == 0) {
    300                 msn_ns_send_adl_start(ic);
    301                 return msn_ns_finish_login(ic);
    302278        } else if (strcmp(cmd[0], "ADL") == 0) {
    303279                if (num_parts >= 3 && strcmp(cmd[2], "OK") == 0) {
     
    305281                        return msn_ns_finish_login(ic);
    306282                } else if (num_parts >= 3) {
    307                         handler->msglen = atoi(cmd[2]);
    308                 }
    309         } else if (strcmp(cmd[0], "PRP") == 0) {
    310                 imcb_connected(ic);
     283                        md->msglen = atoi(cmd[2]);
     284                }
    311285        } else if (strcmp(cmd[0], "CHL") == 0) {
    312286                char *resp;
     
    326300                g_free(resp);
    327301                return st;
    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                 }
     302        } else if (strcmp(cmd[0], "QRY") == 0) {
     303                /* CONGRATULATIONS */
    417304        } else if (strcmp(cmd[0], "OUT") == 0) {
    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);
     305                imcb_error(ic, "Session terminated by remote server (%s)", cmd[1] ? cmd[1] : "reason unknown");
     306                imc_logout(ic, TRUE);
    431307                return(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) {
     308        } else if (strcmp(cmd[0], "GCF") == 0) {
    485309                /* Coming up is cmd[2] bytes of stuff we're supposed to
    486310                   censore. Meh. */
    487                 handler->msglen = atoi(cmd[2]);
    488         } else if (strcmp(cmd[0], "UBX") == 0) {
    489                 /* Status message. */
     311                md->msglen = atoi(cmd[2]);
     312        } else if ((strcmp(cmd[0], "NFY") == 0) || (strcmp(cmd[0], "SDG") == 0)) {
    490313                if (num_parts >= 3) {
    491                         handler->msglen = atoi(cmd[2]);
     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]);
    492319                }
    493320        } else if (strcmp(cmd[0], "NOT") == 0) {
    494                 /* Some kind of notification, poorly documented but
    495                    apparently used to announce address book changes. */
    496321                if (num_parts >= 2) {
    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]);
     322                        md->msglen = atoi(cmd[1]);
    502323                }
    503324        } else if (strcmp(cmd[0], "QNG") == 0) {
     
    516337                /* Oh yes, errors can have payloads too now. Discard them for now. */
    517338                if (num_parts >= 3) {
    518                         handler->msglen = atoi(cmd[2]);
     339                        md->msglen = atoi(cmd[2]);
    519340                }
    520341        } else {
    521                 /* debug( "Received unknown command from main server: %s", cmd[0] ); */
     342                imcb_error(ic, "Received unknown command from main server: %s", cmd[0]);
    522343        }
    523344
     
    525346}
    526347
    527 static 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;
     348int msn_ns_message(struct msn_data *md, char *msg, int msglen, char **cmd, int num_parts)
     349{
     350        struct im_connection *ic = md->ic;
    530351        char *body;
    531352        int blen = 0;
     
    598419                                }
    599420                        } else if (g_strncasecmp(ct, "text/x-msmsgsactivemailnotification", 35) == 0) {
    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);
     421                                /* Notification that a message has been read... Ignore it */
    652422                        } else {
    653423                                debug("Can't handle %s packet from notification server", ct);
     
    656426                        g_free(ct);
    657427                }
    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);
    670428        } else if (strcmp(cmd[0], "ADL") == 0) {
    671429                struct xt_node *adl, *d, *c;
     
    716474                        }
    717475                }
    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);
     476        } else if ((strcmp(cmd[0], "SDG") == 0) || (strcmp(cmd[0], "NFY") == 0)) {
     477                msn_ns_structured_message(md, msg, msglen, cmd);
    744478        }
    745479
    746480        return 1;
     481}
     482
     483static 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
     510cleanup:
     511        g_strfreev(parts);
     512        g_free(action);
     513        g_free(from);
     514        g_free(who);
     515}
     516
     517static 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
     528static 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
     584cleanup:
     585        xt_free_node(body);
    747586}
    748587
     
    768607void msn_auth_got_contact_list(struct im_connection *ic)
    769608{
    770         struct msn_data *md;
    771 
    772609        /* Dead connection? */
    773610        if (g_slist_find(msn_connections, ic) == NULL) {
     
    775612        }
    776613
    777         md = ic->proto_data;
    778         msn_ns_write(ic, -1, "BLP %d %s\r\n", ++md->trId, "BL");
     614        msn_ns_send_adl_start(ic);
     615        msn_ns_finish_login(ic);
    779616}
    780617
    781618static gboolean msn_ns_send_adl_1(gpointer key, gpointer value, gpointer data)
    782619{
    783         struct xt_node *adl = data, *d, *c;
     620        struct xt_node *adl = data, *d, *c, *s;
    784621        struct bee_user *bu = value;
    785622        struct msn_buddy_data *bd = bu->data;
     
    810647        c = xt_new_node("c", NULL, NULL);
    811648        xt_add_attr(c, "n", handle);
    812         xt_add_attr(c, "l", l);
    813649        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);
    814654        xt_insert_child(d, c);
    815655
     
    881721
    882722        if ((md->flags & MSN_DONE_ADL) && (md->flags & MSN_GOT_PROFILE)) {
    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                 }
     723                imcb_connected(ic);
    888724        }
    889725
     
    891727}
    892728
     729// TODO: typing notifications, nudges lol, etc
    893730int msn_ns_sendmessage(struct im_connection *ic, bee_user_t *bu, const char *text)
    894731{
    895732        struct msn_data *md = ic->proto_data;
    896         int type = 0;
    897         char *buf, *handle;
     733        int retval = 0;
     734        char *buf;
    898735
    899736        if (strncmp(text, "\r\r\r", 3) == 0) {
     
    903740        }
    904741
    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 
    928 void 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 }
     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}
Note: See TracChangeset for help on using the changeset viewer.