Changes in / [291c49b:356e2dd]


Ignore:
Files:
1 added
1 deleted
8 edited

Legend:

Unmodified
Added
Removed
  • lib/misc.c

    r291c49b r356e2dd  
    719719                        }
    720720
    721                         /* Make sure we're still inside the string */
    722                         if (i >= len) {
    723                                 return(NULL);
    724                         }
    725 
    726721                        /* Copy the found data */
    727722                        return(g_strndup(ret, text + i - ret));
  • protocols/msn/Makefile

    r291c49b r356e2dd  
    1313
    1414# [SH] Program variables
    15 objects = msn.o msn_util.o ns.o sb.o soap.o tables.o
     15objects = msn.o msn_util.o ns.o soap.o tables.o gw.o
    1616
    1717LFLAGS += -r
  • protocols/msn/msn.c

    r291c49b r356e2dd  
    3030int msn_chat_id;
    3131GSList *msn_connections;
    32 GSList *msn_switchboards;
    3332
    3433static char *set_eval_display_name(set_t *set, char *value);
     
    4847
    4948        set_add(&acc->set, "mail_notifications", "false", set_eval_bool, acc);
    50         set_add(&acc->set, "switchboard_keepalives", "false", set_eval_bool, acc);
    5149
    5250        acc->flags |= ACC_FLAG_AWAY_MESSAGE | ACC_FLAG_STATUS_MESSAGE |
     
    6462
    6563        if (!server) {
    66                 imcb_error(ic, "The msn protocol is disabled in this version because most servers disabled MSNP18 over port 1863.");
    67                 imcb_error(ic, "If you find a working server, you can change the 'server' setting of this account. Good luck!");
    68                 imcb_error(ic, "See also: http://ismsndeadyet.com/"); // shameless plug
    69                 imc_logout(ic, FALSE);
    70                 return;
     64                server = "geo.gateway.messenger.live.com";
    7165        }
    7266
     
    8074        md->away_state = msn_away_state_list;
    8175        md->domaintree = g_tree_new(msn_domaintree_cmp);
    82         md->ns->fd = -1;
     76        md->fd = -1;
     77        md->is_http = TRUE;
    8378
    8479        msn_connections = g_slist_prepend(msn_connections, ic);
    8580
    8681        imcb_log(ic, "Connecting");
    87         msn_ns_connect(ic, md->ns, server,
     82        msn_ns_connect(ic, server,
    8883                       set_getint(&ic->acc->set, "port"));
    8984}
     
    9691
    9792        if (md) {
    98                 msn_ns_close(md->ns);
    99 
    100                 while (md->switchboards) {
    101                         msn_sb_destroy(md->switchboards->data);
    102                 }
    103 
    104                 msn_msgq_purge(ic, &md->msgq);
     93                msn_ns_close(md);
     94
    10595                msn_soapq_flush(ic, FALSE);
    10696
     
    154144{
    155145        struct bee_user *bu = bee_user_by_handle(ic->bee, ic, who);
    156         struct msn_buddy_data *bd = bu ? bu->data : NULL;
    157         struct msn_switchboard *sb;
    158146
    159147#ifdef DEBUG
    160148        if (strcmp(who, "raw") == 0) {
    161149                msn_ns_write(ic, -1, "%s\r\n", message);
    162         } else
     150                return 0;
     151        }
    163152#endif
    164         if (bd && bd->flags & MSN_BUDDY_FED) {
    165                 msn_ns_sendmessage(ic, bu, message);
    166         } else if ((sb = msn_sb_by_handle(ic, who))) {
    167                 return(msn_sb_sendmessage(sb, message));
    168         } else {
    169                 struct msn_message *m;
    170 
    171                 /* Create a message. We have to arrange a usable switchboard, and send the message later. */
    172                 m = g_new0(struct msn_message, 1);
    173                 m->who = g_strdup(who);
    174                 m->text = g_strdup(message);
    175 
    176                 return msn_sb_write_msg(ic, m);
    177         }
    178 
     153
     154        msn_ns_sendmessage(ic, bu, message);
    179155        return(0);
    180156}
     
    198174static void msn_set_away(struct im_connection *ic, char *state, char *message)
    199175{
    200         char *uux;
    201176        struct msn_data *md = ic->proto_data;
     177        char *nick, *psm, *idle, *statecode, *body, *buf;
    202178
    203179        if (state == NULL) {
     
    207183        }
    208184
    209         if (!msn_ns_write(ic, -1, "CHG %d %s %d:%02d\r\n", ++md->trId, md->away_state->code, MSN_CAP1, MSN_CAP2)) {
    210                 return;
    211         }
    212 
    213         uux = g_markup_printf_escaped("<EndpointData><Capabilities>%d:%02d"
    214                                       "</Capabilities></EndpointData>",
    215                                       MSN_CAP1, MSN_CAP2);
    216         msn_ns_write(ic, -1, "UUX %d %zd\r\n%s", ++md->trId, strlen(uux), uux);
    217         g_free(uux);
    218 
    219         uux = g_markup_printf_escaped("<PrivateEndpointData><EpName>%s</EpName>"
    220                                       "<Idle>%s</Idle><ClientType>%d</ClientType>"
    221                                       "<State>%s</State></PrivateEndpointData>",
    222                                       md->uuid,
    223                                       strcmp(md->away_state->code, "IDL") ? "false" : "true",
    224                                       1,  /* ? */
    225                                       md->away_state->code);
    226         msn_ns_write(ic, -1, "UUX %d %zd\r\n%s", ++md->trId, strlen(uux), uux);
    227         g_free(uux);
    228 
    229         uux = g_markup_printf_escaped("<Data><DDP></DDP><PSM>%s</PSM>"
    230                                       "<CurrentMedia></CurrentMedia>"
    231                                       "<MachineGuid>%s</MachineGuid></Data>",
    232                                       message ? message : "", md->uuid);
    233         msn_ns_write(ic, -1, "UUX %d %zd\r\n%s", ++md->trId, strlen(uux), uux);
    234         g_free(uux);
     185        statecode = (char *) md->away_state->code;
     186        nick = set_getstr(&ic->acc->set, "display_name");
     187        psm = message ? message : "";
     188        idle = (strcmp(statecode, "IDL") == 0) ? "false" : "true";
     189
     190        body = g_markup_printf_escaped(MSN_PUT_USER_BODY,
     191                nick, psm, psm, md->uuid, statecode, md->uuid, idle, statecode,
     192                MSN_CAP1, MSN_CAP2, MSN_CAP1, MSN_CAP2
     193        );
     194
     195        buf = g_strdup_printf(MSN_PUT_HEADERS, ic->acc->user, ic->acc->user, md->uuid,
     196                "/user", "application/user+xml",
     197                strlen(body), body);
     198        msn_ns_write(ic, -1, "PUT %d %zd\r\n%s", ++md->trId, strlen(buf), buf);
     199
     200        g_free(buf);
     201        g_free(body);
    235202}
    236203
     
    258225static void msn_chat_msg(struct groupchat *c, char *message, int flags)
    259226{
    260         struct msn_switchboard *sb = msn_sb_by_chat(c);
    261 
    262         if (sb) {
    263                 msn_sb_sendmessage(sb, message);
    264         }
    265         /* FIXME: Error handling (although this can't happen unless something's
    266            already severely broken) disappeared here! */
     227        /* TODO: groupchats*/
    267228}
    268229
    269230static void msn_chat_invite(struct groupchat *c, char *who, char *message)
    270231{
    271         struct msn_switchboard *sb = msn_sb_by_chat(c);
    272 
    273         if (sb) {
    274                 msn_sb_write(sb, "CAL %d %s\r\n", ++sb->trId, who);
    275         }
     232        /* TODO: groupchats*/
    276233}
    277234
    278235static void msn_chat_leave(struct groupchat *c)
    279236{
    280         struct msn_switchboard *sb = msn_sb_by_chat(c);
    281 
    282         if (sb) {
    283                 msn_sb_write(sb, "OUT\r\n");
    284         }
     237        /* TODO: groupchats*/
    285238}
    286239
    287240static struct groupchat *msn_chat_with(struct im_connection *ic, char *who)
    288241{
    289         struct msn_switchboard *sb;
     242        /* TODO: groupchats*/
    290243        struct groupchat *c = imcb_chat_new(ic, who);
    291 
    292         if ((sb = msn_sb_by_handle(ic, who))) {
    293                 debug("Converting existing switchboard to %s to a groupchat", who);
    294                 return msn_sb_to_chat(sb);
    295         } else {
    296                 struct msn_message *m;
    297 
    298                 /* Create a magic message. This is quite hackish, but who cares? :-P */
    299                 m = g_new0(struct msn_message, 1);
    300                 m->who = g_strdup(who);
    301                 m->text = g_strdup(GROUPCHAT_SWITCHBOARD_MESSAGE);
    302 
    303                 msn_sb_write_msg(ic, m);
    304 
    305                 return c;
    306         }
     244        return c;
    307245}
    308246
     
    324262static void msn_add_deny(struct im_connection *ic, char *who)
    325263{
    326         struct msn_switchboard *sb;
    327 
    328264        msn_buddy_list_add(ic, MSN_BUDDY_BL, who, who, NULL);
    329 
    330         /* If there's still a conversation with this person, close it. */
    331         if ((sb = msn_sb_by_handle(ic, who))) {
    332                 msn_sb_destroy(sb);
    333         }
    334265}
    335266
  • protocols/msn/msn.h

    r291c49b r356e2dd  
    3232#define NUDGE_MESSAGE "\r\r\rSHAKE THAT THING\r\r\r"
    3333#define GROUPCHAT_SWITCHBOARD_MESSAGE "\r\r\rME WANT TALK TO MANY PEOPLE\r\r\r"
    34 #define SB_KEEPALIVE_MESSAGE "\r\r\rDONT HANG UP ON ME!\r\r\r"
    3534
    3635#ifdef DEBUG_MSN
     
    6059#define MSNP11_PROD_KEY "C1BX{V4W}Q3*10SM"
    6160#define MSNP11_PROD_ID  "PROD0120PW!CCV9@"
    62 #define MSNP_VER        "MSNP18"
     61#define MSNP_VER        "MSNP21"
    6362#define MSNP_BUILD      "14.0.8117.416"
    6463
     
    6867#define MSN_CAP2        0x0000
    6968
    70 #define MSN_MESSAGE_HEADERS "MIME-Version: 1.0\r\n" \
     69#define MSN_BASE_HEADERS \
     70        "Routing: 1.0\r\n" \
     71        "To: 1:%s\r\n" \
     72        "From: 1:%s;epid={%s}\r\n" \
     73        "\r\n" \
     74        "Reliability: 1.0\r\n" \
     75        "\r\n"
     76
     77#define MSN_MESSAGE_HEADERS MSN_BASE_HEADERS \
     78        "Messaging: 2.0\r\n" \
     79        "Message-Type: Text\r\n" \
     80        "Content-Length: %zd\r\n" \
    7181        "Content-Type: text/plain; charset=UTF-8\r\n" \
    72         "User-Agent: BitlBee " BITLBEE_VERSION "\r\n" \
    73         "X-MMS-IM-Format: FN=MS%20Shell%20Dlg; EF=; CO=0; CS=0; PF=0\r\n" \
    74         "\r\n"
     82        "X-MMS-IM-Format: FN=Segoe%%20UI; EF=; CO=0; CS=0; PF=0\r\n" \
     83        "\r\n" \
     84        "%s"
     85
     86#define MSN_PUT_HEADERS MSN_BASE_HEADERS \
     87        "Publication: 1.0\r\n" \
     88        "Uri: %s\r\n" \
     89        "Content-Type: %s\r\n" \
     90        "Content-Length: %zd\r\n" \
     91        "\r\n" \
     92        "%s"
     93
     94#define MSN_PUT_USER_BODY \
     95        "<user>" \
     96        "<s n=\"PE\"><UserTileLocation></UserTileLocation><FriendlyName>%s</FriendlyName><PSM>%s</PSM><DDP></DDP>" \
     97        "<Scene></Scene><ASN></ASN><ColorScheme>-3</ColorScheme><BDG></BDG><RUM>%s</RUM><RUL></RUL><RLT>0</RLT>" \
     98        "<RID></RID><SUL></SUL><MachineGuid>%s</MachineGuid></s>" \
     99        "<s n=\"IM\"><Status>%s</Status><CurrentMedia></CurrentMedia></s>" \
     100        "<sep n=\"PD\"><ClientType>1</ClientType><EpName>%s</EpName><Idle>%s</Idle><State>%s</State></sep>" \
     101        "<sep n=\"PE\"><VER>BitlBee:" BITLBEE_VERSION "</VER><TYP>1</TYP><Capabilities>%d:%d</Capabilities></sep>" \
     102        "<sep n=\"IM\"><Capabilities>%d:%d</Capabilities></sep>" \
     103        "</user>"
    75104
    76105#define MSN_TYPING_HEADERS "MIME-Version: 1.0\r\n" \
     
    84113        "ID: 1\r\n" \
    85114        "\r\n"
    86 
    87 #define MSN_SB_KEEPALIVE_HEADERS "MIME-Version: 1.0\r\n" \
    88         "Content-Type: text/x-ping\r\n" \
    89         "\r\n\r\n"
    90115
    91116#define PROFILE_URL "http://members.msn.com/"
     
    99124} msn_flags_t;
    100125
    101 struct msn_handler_data {
     126struct msn_gw {
     127        char *last_host;
     128        int port;
     129        gboolean ssl;
     130
     131        char *session_id;
     132
     133        GByteArray *in;
     134        GByteArray *out;
     135
     136        int poll_timeout;
     137
     138        b_event_handler callback;
     139
     140        struct im_connection *ic;
     141        struct msn_data *md;
     142
     143        gboolean open;
     144        gboolean waiting;
     145        gboolean polling;
     146};
     147
     148struct msn_data {
    102149        int fd, inpa;
    103150        int rxlen;
     
    107154        char *cmd_text;
    108155
    109         /* Either ic or sb */
    110         gpointer data;
    111 
    112         int (*exec_command) (struct msn_handler_data *handler, char **cmd, int count);
    113         int (*exec_message) (struct msn_handler_data *handler, char *msg, int msglen, char **cmd, int count);
    114 };
    115 
    116 struct msn_data {
    117156        struct im_connection *ic;
    118157
    119         struct msn_handler_data ns[1];
    120158        msn_flags_t flags;
    121159
     
    126164
    127165        GSList *msgq, *grpq, *soapq;
    128         GSList *switchboards;
    129         int sb_failures;
    130         time_t first_sb_failure;
    131166
    132167        const struct msn_away_state *away_state;
     
    139174        GTree *domaintree;
    140175        int adl_todo;
    141 };
    142 
    143 struct msn_switchboard {
    144         struct im_connection *ic;
    145 
    146         /* The following two are also in the handler. TODO: Clean up. */
    147         int fd;
    148         gint inp;
    149         struct msn_handler_data *handler;
    150         gint keepalive;
    151 
    152         int trId;
    153         int ready;
    154 
    155         int session;
    156         char *key;
    157 
    158         GSList *msgq;
    159         char *who;
    160         struct groupchat *chat;
     176
     177        gboolean is_http;
     178        struct msn_gw *gw;
    161179};
    162180
     
    205223#define STATUS_FATAL            1
    206224#define STATUS_SB_FATAL         2
    207 #define STATUS_SB_IM_SPARE      4       /* Make one-to-one conversation switchboard available again, invite failed. */
    208 #define STATUS_SB_CHAT_SPARE    8       /* Same, but also for groupchats (not used yet). */
    209225
    210226extern int msn_chat_id;
     
    218234   before doing *anything* else. */
    219235extern GSList *msn_connections;
    220 extern GSList *msn_switchboards;
    221236
    222237/* ns.c */
    223238int msn_ns_write(struct im_connection *ic, int fd, const char *fmt, ...) G_GNUC_PRINTF(3, 4);
    224 gboolean msn_ns_connect(struct im_connection *ic, struct msn_handler_data *handler, const char *host, int port);
    225 void msn_ns_close(struct msn_handler_data *handler);
     239gboolean msn_ns_connect(struct im_connection *ic, const char *host, int port);
     240void msn_ns_close(struct msn_data *handler);
    226241void msn_auth_got_passport_token(struct im_connection *ic, const char *token, const char *error);
    227242void msn_auth_got_contact_list(struct im_connection *ic);
    228243int msn_ns_finish_login(struct im_connection *ic);
    229244int msn_ns_sendmessage(struct im_connection *ic, struct bee_user *bu, const char *text);
    230 void msn_ns_oim_send_queue(struct im_connection *ic, GSList **msgq);
     245int msn_ns_command(struct msn_data *md, char **cmd, int num_parts);
     246int msn_ns_message(struct msn_data *md, char *msg, int msglen, char **cmd, int num_parts);
    231247
    232248/* msn_util.c */
     
    235251int msn_buddy_list_remove(struct im_connection *ic, msn_buddy_flags_t list, const char *who, const char *group);
    236252void msn_buddy_ask(bee_user_t *bu);
    237 char **msn_linesplit(char *line);
    238 int msn_handler(struct msn_handler_data *h);
    239 void msn_msgq_purge(struct im_connection *ic, GSList **list);
     253void msn_queue_feed(struct msn_data *h, char *bytes, int st);
     254int msn_handler(struct msn_data *h);
    240255char *msn_p11_challenge(char *challenge);
    241256gint msn_domaintree_cmp(gconstpointer a_, gconstpointer b_);
     
    251266const struct msn_status_code *msn_status_by_number(int number);
    252267
    253 /* sb.c */
    254 int msn_sb_write(struct msn_switchboard *sb, const char *fmt, ...) G_GNUC_PRINTF(2, 3);;
    255 struct msn_switchboard *msn_sb_create(struct im_connection *ic, char *host, int port, char *key, int session);
    256 struct msn_switchboard *msn_sb_by_handle(struct im_connection *ic, const char *handle);
    257 struct msn_switchboard *msn_sb_by_chat(struct groupchat *c);
    258 struct msn_switchboard *msn_sb_spare(struct im_connection *ic);
    259 int msn_sb_sendmessage(struct msn_switchboard *sb, char *text);
    260 struct groupchat *msn_sb_to_chat(struct msn_switchboard *sb);
    261 void msn_sb_destroy(struct msn_switchboard *sb);
    262 gboolean msn_sb_connected(gpointer data, gint source, b_input_condition cond);
    263 int msn_sb_write_msg(struct im_connection *ic, struct msn_message *m);
    264 void msn_sb_start_keepalives(struct msn_switchboard *sb, gboolean initial);
    265 void msn_sb_stop_keepalives(struct msn_switchboard *sb);
     268/* gw.c */
     269struct msn_gw *msn_gw_new(struct im_connection *ic);
     270void msn_gw_free(struct msn_gw *gw);
     271void msn_gw_open(struct msn_gw *gw);
     272ssize_t msn_gw_read(struct msn_gw *gw, char **buf);
     273void msn_gw_write(struct msn_gw *gw, char *buf, size_t len);
    266274
    267275#endif //_MSN_H
  • protocols/msn/msn_util.c

    r291c49b r356e2dd  
    5555
    5656        *groupid = '\0';
    57 #if 0
    58         if (group) {
    59                 int i;
    60                 for (i = 0; i < md->groupcount; i++) {
    61                         if (g_strcasecmp(md->grouplist[i], group) == 0) {
    62                                 g_snprintf(groupid, sizeof(groupid), " %d", i);
    63                                 break;
    64                         }
    65                 }
    66 
    67                 if (*groupid == '\0') {
    68                         /* Have to create this group, it doesn't exist yet. */
    69                         struct msn_groupadd *ga;
    70                         GSList *l;
    71 
    72                         for (l = md->grpq; l; l = l->next) {
    73                                 ga = l->data;
    74                                 if (g_strcasecmp(ga->group, group) == 0) {
    75                                         break;
    76                                 }
    77                         }
    78 
    79                         ga = g_new0(struct msn_groupadd, 1);
    80                         ga->who = g_strdup(who);
    81                         ga->group = g_strdup(group);
    82                         md->grpq = g_slist_prepend(md->grpq, ga);
    83 
    84                         if (l == NULL) {
    85                                 char groupname[strlen(group) + 1];
    86                                 strcpy(groupname, group);
    87                                 http_encode(groupname);
    88                                 g_snprintf(buf, sizeof(buf), "ADG %d %s %d\r\n", ++md->trId, groupname, 0);
    89                                 return msn_write(ic, buf, strlen(buf));
    90                         } else {
    91                                 /* This can happen if the user's doing lots of adds to a
    92                                    new group at once; we're still waiting for the server
    93                                    to confirm group creation. */
    94                                 return 1;
    95                         }
    96                 }
    97         }
    98 #endif
    9957
    10058        if (!((bu = bee_user_by_handle(ic->bee, ic, who)) ||
     
    13290
    13391        *groupid = '\0';
    134 #if 0
    135         if (group) {
    136                 int i;
    137                 for (i = 0; i < md->groupcount; i++) {
    138                         if (g_strcasecmp(md->grouplist[i], group) == 0) {
    139                                 g_snprintf(groupid, sizeof(groupid), " %d", i);
    140                                 break;
    141                         }
    142                 }
    143         }
    144 #endif
    14592
    14693        if (!(bu = bee_user_by_handle(ic->bee, ic, who)) ||
     
    225172}
    226173
    227 /* *NOT* thread-safe, but that's not a problem for now... */
    228 char **msn_linesplit(char *line)
    229 {
    230         static char **ret = NULL;
    231         static int size = 3;
    232         int i, n = 0;
    233 
    234         if (ret == NULL) {
    235                 ret = g_new0(char*, size);
    236         }
    237 
    238         for (i = 0; line[i] && line[i] == ' '; i++) {
    239                 ;
    240         }
    241         if (line[i]) {
    242                 ret[n++] = line + i;
    243                 for (i++; line[i]; i++) {
    244                         if (line[i] == ' ') {
    245                                 line[i] = 0;
    246                         } else if (line[i] != ' ' && !line[i - 1]) {
    247                                 ret[n++] = line + i;
    248                         }
    249 
    250                         if (n >= size) {
    251                                 ret = g_renew(char*, ret, size += 2);
    252                         }
    253                 }
    254         }
    255         ret[n] = NULL;
    256 
    257         return(ret);
     174void msn_queue_feed(struct msn_data *h, char *bytes, int st)
     175{
     176        h->rxq = g_renew(char, h->rxq, h->rxlen + st);
     177        memcpy(h->rxq + h->rxlen, bytes, st);
     178        h->rxlen += st;
     179
     180        if (getenv("BITLBEE_DEBUG")) {
     181                fprintf(stderr, "\n\x1b[92m<<< ");
     182                write(2, bytes , st);
     183                fprintf(stderr, "\x1b[97m");
     184        }
    258185}
    259186
     
    266193                   1: OK */
    267194
    268 int msn_handler(struct msn_handler_data *h)
    269 {
    270         int st;
    271 
    272         h->rxq = g_renew(char, h->rxq, h->rxlen + 1024);
    273         st = read(h->fd, h->rxq + h->rxlen, 1024);
    274         h->rxlen += st;
    275 
    276         if (st <= 0) {
    277                 return(-1);
    278         }
    279 
    280         if (getenv("BITLBEE_DEBUG")) {
    281                 write(2, "->C:", 4);
    282                 write(2, h->rxq + h->rxlen - st, st);
    283         }
     195int msn_handler(struct msn_data *h)
     196{
     197        int st = 1;
    284198
    285199        while (st) {
     
    293207
    294208                                        cmd_text = g_strndup(h->rxq, i);
    295                                         cmd = msn_linesplit(cmd_text);
    296                                         for (count = 0; cmd[count]; count++) {
    297                                                 ;
    298                                         }
    299                                         st = h->exec_command(h, cmd, count);
     209                                        cmd = g_strsplit_set(cmd_text, " ", -1);
     210                                        count = g_strv_length(cmd);
     211
     212                                        st = msn_ns_command(h, cmd, count);
     213
     214                                        g_strfreev(cmd);
    300215                                        g_free(cmd_text);
    301216
     
    320235                        /* If we reached the end of the buffer, there's still an incomplete command there.
    321236                           Return and wait for more data. */
    322                         if (i == h->rxlen && h->rxq[i - 1] != '\r' && h->rxq[i - 1] != '\n') {
     237                        if (i && i == h->rxlen && h->rxq[i - 1] != '\r' && h->rxq[i - 1] != '\n') {
    323238                                break;
    324239                        }
     
    333248
    334249                        msg = g_strndup(h->rxq, h->msglen);
    335                         cmd = msn_linesplit(h->cmd_text);
    336                         for (count = 0; cmd[count]; count++) {
    337                                 ;
    338                         }
    339 
    340                         st = h->exec_message(h, msg, h->msglen, cmd, count);
     250
     251                        cmd = g_strsplit_set(h->cmd_text, " ", -1);
     252                        count = g_strv_length(cmd);
     253
     254                        st = msn_ns_message(h, msg, h->msglen, cmd, count);
     255
     256                        g_strfreev(cmd);
    341257                        g_free(msg);
    342258                        g_free(h->cmd_text);
     
    372288}
    373289
    374 void msn_msgq_purge(struct im_connection *ic, GSList **list)
    375 {
    376         struct msn_message *m;
    377         GString *ret;
    378         GSList *l;
    379         int n = 0;
    380 
    381         l = *list;
    382         if (l == NULL) {
    383                 return;
    384         }
    385 
    386         m = l->data;
    387         ret = g_string_sized_new(1024);
    388         g_string_printf(ret, "Warning: Cleaning up MSN (switchboard) connection with unsent "
    389                         "messages to %s:", m->who ? m->who : "unknown recipient");
    390 
    391         while (l) {
    392                 m = l->data;
    393 
    394                 if (strncmp(m->text, "\r\r\r", 3) != 0) {
    395                         g_string_append_printf(ret, "\n%s", m->text);
    396                         n++;
    397                 }
    398 
    399                 g_free(m->who);
    400                 g_free(m->text);
    401                 g_free(m);
    402 
    403                 l = l->next;
    404         }
    405         g_slist_free(*list);
    406         *list = NULL;
    407 
    408         if (n > 0) {
    409                 imcb_log(ic, "%s", ret->str);
    410         }
    411         g_string_free(ret, TRUE);
    412 }
    413 
    414290/* Copied and heavily modified from http://tmsnc.sourceforge.net/chl.c */
    415291char *msn_p11_challenge(char *challenge)
     
    535411int msn_ns_set_display_name(struct im_connection *ic, const char *value)
    536412{
    537         struct msn_data *md = ic->proto_data;
    538         char fn[strlen(value) * 3 + 1];
    539 
    540         strcpy(fn, value);
    541         http_encode(fn);
    542 
    543         /* Note: We don't actually know if the server accepted the new name,
    544            and won't give proper feedback yet if it doesn't. */
    545         return msn_ns_write(ic, -1, "PRP %d MFN %s\r\n", ++md->trId, fn);
     413        // TODO, implement this through msn_set_away's method
     414        return 1;
    546415}
    547416
  • protocols/msn/ns.c

    r291c49b r356e2dd  
    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                 *msgq = g_slist_remove(*msgq, m);
    947                 g_free(m->who);
    948                 g_free(m->text);
    949                 g_free(m);
    950         }
    951 }
     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}
  • protocols/msn/soap.c

    r291c49b r356e2dd  
    209209                return;
    210210        }
     211        fprintf(stderr, "\n\x1b[90mSOAP:\n");
    211212
    212213        if (headers) {
     
    225226                xt_free_node(xt);
    226227        }
     228        fprintf(stderr, "\n\x1b[97m\n");
    227229}
    228230
  • protocols/msn/tables.c

    r291c49b r356e2dd  
    7373        { 206, "Domain name missing",                                   0 },
    7474        { 207, "Already logged in",                                     0 },
    75         { 208, "Invalid handle",                                        STATUS_SB_IM_SPARE },
     75        { 208, "Invalid handle",                                        0 },
    7676        { 209, "Forbidden nickname",                                    0 },
    7777        { 210, "Buddy list too long",                                   0 },
    7878        { 215, "Handle is already in list",                             0 },
    79         { 216, "Handle is not in list",                                 STATUS_SB_IM_SPARE },
    80         { 217, "Person is off-line or non-existent",                    STATUS_SB_IM_SPARE },
     79        { 216, "Handle is not in list",                                 0 },
     80        { 217, "Person is off-line or non-existent",                    0 },
    8181        { 218, "Already in that mode",                                  0 },
    8282        { 219, "Handle is already in opposite list",                    0 },
     
    113113        { 711, "Write is blocking",                                     STATUS_FATAL },
    114114        { 712, "Session is overloaded",                                 STATUS_FATAL },
    115         { 713, "Calling too rapidly",                                   STATUS_SB_IM_SPARE },
     115        { 713, "Calling too rapidly",                                   0 },
    116116        { 714, "Too many sessions",                                     STATUS_FATAL },
    117117        { 715, "Not expected/Invalid argument/action",                  0 },
Note: See TracChangeset for help on using the changeset viewer.