- Timestamp:
- 2015-04-21T04:04:57Z (10 years ago)
- Children:
- b8c336b
- Parents:
- 291c49b (diff), 71074ac (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. - Location:
- protocols/msn
- Files:
-
- 1 added
- 1 deleted
- 7 edited
Legend:
- Unmodified
- Added
- Removed
-
protocols/msn/Makefile
r291c49b r356e2dd 13 13 14 14 # [SH] Program variables 15 objects = msn.o msn_util.o ns.o s b.o soap.o tables.o15 objects = msn.o msn_util.o ns.o soap.o tables.o gw.o 16 16 17 17 LFLAGS += -r -
protocols/msn/msn.c
r291c49b r356e2dd 30 30 int msn_chat_id; 31 31 GSList *msn_connections; 32 GSList *msn_switchboards;33 32 34 33 static char *set_eval_display_name(set_t *set, char *value); … … 48 47 49 48 set_add(&acc->set, "mail_notifications", "false", set_eval_bool, acc); 50 set_add(&acc->set, "switchboard_keepalives", "false", set_eval_bool, acc);51 49 52 50 acc->flags |= ACC_FLAG_AWAY_MESSAGE | ACC_FLAG_STATUS_MESSAGE | … … 64 62 65 63 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"; 71 65 } 72 66 … … 80 74 md->away_state = msn_away_state_list; 81 75 md->domaintree = g_tree_new(msn_domaintree_cmp); 82 md->ns->fd = -1; 76 md->fd = -1; 77 md->is_http = TRUE; 83 78 84 79 msn_connections = g_slist_prepend(msn_connections, ic); 85 80 86 81 imcb_log(ic, "Connecting"); 87 msn_ns_connect(ic, md->ns,server,82 msn_ns_connect(ic, server, 88 83 set_getint(&ic->acc->set, "port")); 89 84 } … … 96 91 97 92 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 105 95 msn_soapq_flush(ic, FALSE); 106 96 … … 154 144 { 155 145 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;158 146 159 147 #ifdef DEBUG 160 148 if (strcmp(who, "raw") == 0) { 161 149 msn_ns_write(ic, -1, "%s\r\n", message); 162 } else 150 return 0; 151 } 163 152 #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); 179 155 return(0); 180 156 } … … 198 174 static void msn_set_away(struct im_connection *ic, char *state, char *message) 199 175 { 200 char *uux;201 176 struct msn_data *md = ic->proto_data; 177 char *nick, *psm, *idle, *statecode, *body, *buf; 202 178 203 179 if (state == NULL) { … … 207 183 } 208 184 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); 235 202 } 236 203 … … 258 225 static void msn_chat_msg(struct groupchat *c, char *message, int flags) 259 226 { 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*/ 267 228 } 268 229 269 230 static void msn_chat_invite(struct groupchat *c, char *who, char *message) 270 231 { 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*/ 276 233 } 277 234 278 235 static void msn_chat_leave(struct groupchat *c) 279 236 { 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*/ 285 238 } 286 239 287 240 static struct groupchat *msn_chat_with(struct im_connection *ic, char *who) 288 241 { 289 struct msn_switchboard *sb;242 /* TODO: groupchats*/ 290 243 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; 307 245 } 308 246 … … 324 262 static void msn_add_deny(struct im_connection *ic, char *who) 325 263 { 326 struct msn_switchboard *sb;327 328 264 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 }334 265 } 335 266 -
protocols/msn/msn.h
r291c49b r356e2dd 32 32 #define NUDGE_MESSAGE "\r\r\rSHAKE THAT THING\r\r\r" 33 33 #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"35 34 36 35 #ifdef DEBUG_MSN … … 60 59 #define MSNP11_PROD_KEY "C1BX{V4W}Q3*10SM" 61 60 #define MSNP11_PROD_ID "PROD0120PW!CCV9@" 62 #define MSNP_VER "MSNP 18"61 #define MSNP_VER "MSNP21" 63 62 #define MSNP_BUILD "14.0.8117.416" 64 63 … … 68 67 #define MSN_CAP2 0x0000 69 68 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" \ 71 81 "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>" 75 104 76 105 #define MSN_TYPING_HEADERS "MIME-Version: 1.0\r\n" \ … … 84 113 "ID: 1\r\n" \ 85 114 "\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"90 115 91 116 #define PROFILE_URL "http://members.msn.com/" … … 99 124 } msn_flags_t; 100 125 101 struct msn_handler_data { 126 struct 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 148 struct msn_data { 102 149 int fd, inpa; 103 150 int rxlen; … … 107 154 char *cmd_text; 108 155 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 {117 156 struct im_connection *ic; 118 157 119 struct msn_handler_data ns[1];120 158 msn_flags_t flags; 121 159 … … 126 164 127 165 GSList *msgq, *grpq, *soapq; 128 GSList *switchboards;129 int sb_failures;130 time_t first_sb_failure;131 166 132 167 const struct msn_away_state *away_state; … … 139 174 GTree *domaintree; 140 175 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; 161 179 }; 162 180 … … 205 223 #define STATUS_FATAL 1 206 224 #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). */209 225 210 226 extern int msn_chat_id; … … 218 234 before doing *anything* else. */ 219 235 extern GSList *msn_connections; 220 extern GSList *msn_switchboards;221 236 222 237 /* ns.c */ 223 238 int 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);239 gboolean msn_ns_connect(struct im_connection *ic, const char *host, int port); 240 void msn_ns_close(struct msn_data *handler); 226 241 void msn_auth_got_passport_token(struct im_connection *ic, const char *token, const char *error); 227 242 void msn_auth_got_contact_list(struct im_connection *ic); 228 243 int msn_ns_finish_login(struct im_connection *ic); 229 244 int 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); 245 int msn_ns_command(struct msn_data *md, char **cmd, int num_parts); 246 int msn_ns_message(struct msn_data *md, char *msg, int msglen, char **cmd, int num_parts); 231 247 232 248 /* msn_util.c */ … … 235 251 int msn_buddy_list_remove(struct im_connection *ic, msn_buddy_flags_t list, const char *who, const char *group); 236 252 void 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); 253 void msn_queue_feed(struct msn_data *h, char *bytes, int st); 254 int msn_handler(struct msn_data *h); 240 255 char *msn_p11_challenge(char *challenge); 241 256 gint msn_domaintree_cmp(gconstpointer a_, gconstpointer b_); … … 251 266 const struct msn_status_code *msn_status_by_number(int number); 252 267 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 */ 269 struct msn_gw *msn_gw_new(struct im_connection *ic); 270 void msn_gw_free(struct msn_gw *gw); 271 void msn_gw_open(struct msn_gw *gw); 272 ssize_t msn_gw_read(struct msn_gw *gw, char **buf); 273 void msn_gw_write(struct msn_gw *gw, char *buf, size_t len); 266 274 267 275 #endif //_MSN_H -
protocols/msn/msn_util.c
r291c49b r356e2dd 55 55 56 56 *groupid = '\0'; 57 #if 058 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 a92 new group at once; we're still waiting for the server93 to confirm group creation. */94 return 1;95 }96 }97 }98 #endif99 57 100 58 if (!((bu = bee_user_by_handle(ic->bee, ic, who)) || … … 132 90 133 91 *groupid = '\0'; 134 #if 0135 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 #endif145 92 146 93 if (!(bu = bee_user_by_handle(ic->bee, ic, who)) || … … 225 172 } 226 173 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); 174 void 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 } 258 185 } 259 186 … … 266 193 1: OK */ 267 194 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 } 195 int msn_handler(struct msn_data *h) 196 { 197 int st = 1; 284 198 285 199 while (st) { … … 293 207 294 208 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); 300 215 g_free(cmd_text); 301 216 … … 320 235 /* If we reached the end of the buffer, there's still an incomplete command there. 321 236 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') { 323 238 break; 324 239 } … … 333 248 334 249 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); 341 257 g_free(msg); 342 258 g_free(h->cmd_text); … … 372 288 } 373 289 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 414 290 /* Copied and heavily modified from http://tmsnc.sourceforge.net/chl.c */ 415 291 char *msn_p11_challenge(char *challenge) … … 535 411 int msn_ns_set_display_name(struct im_connection *ic, const char *value) 536 412 { 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; 546 415 } 547 416 -
protocols/msn/ns.c
r291c49b r356e2dd 35 35 static gboolean msn_ns_connected(gpointer data, gint source, b_input_condition cond); 36 36 static 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);39 37 40 38 static void msn_ns_send_adl_start(struct im_connection *ic); 41 39 static void msn_ns_send_adl(struct im_connection *ic); 40 static void msn_ns_structured_message(struct msn_data *md, char *msg, int msglen, char **cmd); 41 static void msn_ns_sdg(struct msn_data *md, char *who, char **parts, char *action); 42 static void msn_ns_nfy(struct msn_data *md, char *who, char **parts, char *action, gboolean is_put); 42 43 43 44 int msn_ns_write(struct im_connection *ic, int fd, const char *fmt, ...) … … 54 55 55 56 if (fd < 0) { 56 fd = md-> ns->fd;57 fd = md->fd; 57 58 } 58 59 59 60 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); 61 62 } 62 63 63 64 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 65 73 g_free(out); 66 74 if (st != len) { … … 73 81 } 74 82 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) { 83 gboolean msn_ns_connect(struct im_connection *ic, const char *host, int port) 84 { 85 struct msn_data *md = ic->proto_data; 86 87 if (md->fd >= 0) { 88 closesocket(md->fd); 89 } 90 91 if (md->is_http) { 92 md->gw = msn_gw_new(ic); 93 md->gw->callback = msn_ns_callback; 94 msn_ns_connected(md, -1, B_EV_IO_READ); 95 } else { 96 md->fd = proxy_connect(host, port, msn_ns_connected, md); 97 if (md->fd < 0) { 98 imcb_error(ic, "Could not connect to server"); 99 imc_logout(ic, TRUE); 100 return FALSE; 101 } 102 } 103 104 return TRUE; 105 } 106 107 static gboolean msn_ns_connected(gpointer data, gint source, b_input_condition cond) 108 { 109 struct msn_data *md = data; 110 struct im_connection *ic = md->ic; 111 112 if (source == -1 && !md->is_http) { 86 113 imcb_error(ic, "Could not connect to server"); 87 114 imc_logout(ic, TRUE); … … 89 116 } 90 117 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); 115 121 116 122 if (md->uuid == NULL) { … … 130 136 131 137 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 } 133 141 imcb_log(ic, "Connected to server, waiting for reply"); 134 142 } … … 137 145 } 138 146 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; 147 void msn_ns_close(struct msn_data *md) 148 { 149 if (md->gw) { 150 msn_gw_free(md->gw); 151 } 152 if (md->fd >= 0) { 153 closesocket(md->fd); 154 b_event_remove(md->inpa); 155 } 156 157 md->fd = md->inpa = -1; 158 g_free(md->rxq); 159 g_free(md->cmd_text); 160 161 md->rxlen = 0; 162 md->rxq = NULL; 163 md->cmd_text = NULL; 153 164 } 154 165 155 166 static gboolean msn_ns_callback(gpointer data, gint source, b_input_condition cond) 156 167 { 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) { 161 181 imcb_error(ic, "Error while reading from server"); 162 182 imc_logout(ic, TRUE); 163 164 183 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 197 int msn_ns_command(struct msn_data *md, char **cmd, int num_parts) 198 { 199 struct im_connection *ic = md->ic; 174 200 175 201 if (num_parts == 0) { … … 185 211 } 186 212 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", 188 214 ++md->trId, ic->acc->user)); 189 215 } else if (strcmp(cmd[0], "CVR") == 0) { 190 216 /* 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); 192 218 } else if (strcmp(cmd[0], "XFR") == 0) { 193 219 char *server; … … 195 221 196 222 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; 199 225 200 226 server = strchr(cmd[3], ':'); … … 209 235 210 236 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); 259 238 } else { 260 239 imcb_error(ic, "Syntax error"); … … 290 269 } 291 270 292 handler->msglen = atoi(cmd[3]);293 294 if ( handler->msglen <= 0) {271 md->msglen = atoi(cmd[3]); 272 273 if (md->msglen <= 0) { 295 274 imcb_error(ic, "Syntax error"); 296 275 imc_logout(ic, TRUE); 297 276 return(0); 298 277 } 299 } else if (strcmp(cmd[0], "BLP") == 0) {300 msn_ns_send_adl_start(ic);301 return msn_ns_finish_login(ic);302 278 } else if (strcmp(cmd[0], "ADL") == 0) { 303 279 if (num_parts >= 3 && strcmp(cmd[2], "OK") == 0) { … … 305 281 return msn_ns_finish_login(ic); 306 282 } 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 } 311 285 } else if (strcmp(cmd[0], "CHL") == 0) { 312 286 char *resp; … … 326 300 g_free(resp); 327 301 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 */ 417 304 } 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); 431 307 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) { 485 309 /* Coming up is cmd[2] bytes of stuff we're supposed to 486 310 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)) { 490 313 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]); 492 319 } 493 320 } else if (strcmp(cmd[0], "NOT") == 0) { 494 /* Some kind of notification, poorly documented but495 apparently used to announce address book changes. */496 321 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]); 502 323 } 503 324 } else if (strcmp(cmd[0], "QNG") == 0) { … … 516 337 /* Oh yes, errors can have payloads too now. Discard them for now. */ 517 338 if (num_parts >= 3) { 518 handler->msglen = atoi(cmd[2]);339 md->msglen = atoi(cmd[2]); 519 340 } 520 341 } 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]); 522 343 } 523 344 … … 525 346 } 526 347 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;348 int msn_ns_message(struct msn_data *md, char *msg, int msglen, char **cmd, int num_parts) 349 { 350 struct im_connection *ic = md->ic; 530 351 char *body; 531 352 int blen = 0; … … 598 419 } 599 420 } 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 */ 652 422 } else { 653 423 debug("Can't handle %s packet from notification server", ct); … … 656 426 g_free(ct); 657 427 } 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);670 428 } else if (strcmp(cmd[0], "ADL") == 0) { 671 429 struct xt_node *adl, *d, *c; … … 716 474 } 717 475 } 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); 744 478 } 745 479 746 480 return 1; 481 } 482 483 static void msn_ns_structured_message(struct msn_data *md, char *msg, int msglen, char **cmd) 484 { 485 char **parts = NULL; 486 char *semicolon = NULL; 487 char *action = NULL; 488 char *from = NULL; 489 char *who = NULL; 490 491 parts = g_strsplit(msg, "\r\n\r\n", 4); 492 493 if (!(from = get_rfc822_header(parts[0], "From", 0))) { 494 goto cleanup; 495 } 496 497 /* either the semicolon or the end of the string */ 498 semicolon = strchr(from, ';') ? : (from + strlen(from)); 499 500 who = g_strndup(from + 2, semicolon - from - 2); 501 502 if ((strcmp(cmd[0], "SDG") == 0) && (action = get_rfc822_header(parts[2], "Message-Type", 0))) { 503 msn_ns_sdg(md, who, parts, action); 504 505 } else if ((strcmp(cmd[0], "NFY") == 0) && (action = get_rfc822_header(parts[2], "Uri", 0))) { 506 gboolean is_put = (strcmp(cmd[1], "PUT") == 0); 507 msn_ns_nfy(md, who, parts, action, is_put); 508 } 509 510 cleanup: 511 g_strfreev(parts); 512 g_free(action); 513 g_free(from); 514 g_free(who); 515 } 516 517 static void msn_ns_sdg(struct msn_data *md, char *who, char **parts, char *action) 518 { 519 struct im_connection *ic = md->ic; 520 521 if (strcmp(action, "Control/Typing") == 0) { 522 imcb_buddy_typing(ic, who, OPT_TYPING); 523 } else if (strcmp(action, "Text") == 0) { 524 imcb_buddy_msg(ic, who, parts[3], 0, 0); 525 } 526 } 527 528 static void msn_ns_nfy(struct msn_data *md, char *who, char **parts, char *action, gboolean is_put) 529 { 530 struct im_connection *ic = md->ic; 531 struct xt_node *body = NULL; 532 struct xt_node *s = NULL; 533 const char *state = NULL; 534 char *nick = NULL; 535 char *psm = NULL; 536 int flags = OPT_LOGGED_IN; 537 538 if (strcmp(action, "/user") != 0) { 539 return; 540 } 541 542 if (!(body = xt_from_string(parts[3], 0))) { 543 goto cleanup; 544 } 545 546 s = body->children; 547 while ((s = xt_find_node(s, "s"))) { 548 struct xt_node *s2; 549 char *n = xt_find_attr(s, "n"); /* service name: IM, PE, etc */ 550 551 if (strcmp(n, "IM") == 0) { 552 /* IM has basic presence information */ 553 if (!is_put) { 554 /* NFY DEL with a <s> usually means log out from the last endpoint */ 555 flags &= ~OPT_LOGGED_IN; 556 break; 557 } 558 559 s2 = xt_find_node(s->children, "Status"); 560 if (s2 && s2->text_len) { 561 const struct msn_away_state *msn_state = msn_away_state_by_code(s2->text); 562 state = msn_state->name; 563 if (msn_state != msn_away_state_list) { 564 flags |= OPT_AWAY; 565 } 566 } 567 } else if (strcmp(n, "PE") == 0) { 568 if ((s2 = xt_find_node(s->children, "PSM")) && s2->text_len) { 569 psm = s2->text; 570 } 571 if ((s2 = xt_find_node(s->children, "FriendlyName")) && s2->text_len) { 572 nick = s2->text; 573 } 574 } 575 s = s->next; 576 } 577 578 imcb_buddy_status(ic, who, flags, state, psm); 579 580 if (nick) { 581 imcb_rename_buddy(ic, who, nick); 582 } 583 584 cleanup: 585 xt_free_node(body); 747 586 } 748 587 … … 768 607 void msn_auth_got_contact_list(struct im_connection *ic) 769 608 { 770 struct msn_data *md;771 772 609 /* Dead connection? */ 773 610 if (g_slist_find(msn_connections, ic) == NULL) { … … 775 612 } 776 613 777 m d = 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); 779 616 } 780 617 781 618 static gboolean msn_ns_send_adl_1(gpointer key, gpointer value, gpointer data) 782 619 { 783 struct xt_node *adl = data, *d, *c ;620 struct xt_node *adl = data, *d, *c, *s; 784 621 struct bee_user *bu = value; 785 622 struct msn_buddy_data *bd = bu->data; … … 810 647 c = xt_new_node("c", NULL, NULL); 811 648 xt_add_attr(c, "n", handle); 812 xt_add_attr(c, "l", l);813 649 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); 814 654 xt_insert_child(d, c); 815 655 … … 881 721 882 722 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); 888 724 } 889 725 … … 891 727 } 892 728 729 // TODO: typing notifications, nudges lol, etc 893 730 int msn_ns_sendmessage(struct im_connection *ic, bee_user_t *bu, const char *text) 894 731 { 895 732 struct msn_data *md = ic->proto_data; 896 int type= 0;897 char *buf , *handle;733 int retval = 0; 734 char *buf; 898 735 899 736 if (strncmp(text, "\r\r\r", 3) == 0) { … … 903 740 } 904 741 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 209 209 return; 210 210 } 211 fprintf(stderr, "\n\x1b[90mSOAP:\n"); 211 212 212 213 if (headers) { … … 225 226 xt_free_node(xt); 226 227 } 228 fprintf(stderr, "\n\x1b[97m\n"); 227 229 } 228 230 -
protocols/msn/tables.c
r291c49b r356e2dd 73 73 { 206, "Domain name missing", 0 }, 74 74 { 207, "Already logged in", 0 }, 75 { 208, "Invalid handle", STATUS_SB_IM_SPARE},75 { 208, "Invalid handle", 0 }, 76 76 { 209, "Forbidden nickname", 0 }, 77 77 { 210, "Buddy list too long", 0 }, 78 78 { 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 }, 81 81 { 218, "Already in that mode", 0 }, 82 82 { 219, "Handle is already in opposite list", 0 }, … … 113 113 { 711, "Write is blocking", STATUS_FATAL }, 114 114 { 712, "Session is overloaded", STATUS_FATAL }, 115 { 713, "Calling too rapidly", STATUS_SB_IM_SPARE},115 { 713, "Calling too rapidly", 0 }, 116 116 { 714, "Too many sessions", STATUS_FATAL }, 117 117 { 715, "Not expected/Invalid argument/action", 0 },
Note: See TracChangeset
for help on using the changeset viewer.