void msn_control_msg(MsnCmdProc *cmdproc, MsnMessage *msg) { PurpleConnection *gc; char *passport; gc = purple_account_get_connection(cmdproc->session->account); passport = msg->remote_user; if (msn_message_get_header_value(msg, "TypingUser") == NULL) return; if (cmdproc->servconn->type == MSN_SERVCONN_SB) { MsnSwitchBoard *swboard = cmdproc->data; if (swboard->current_users == 1) { purple_serv_got_typing(gc, passport, MSN_TYPING_RECV_TIMEOUT, PURPLE_IM_TYPING); } } else { purple_serv_got_typing(gc, passport, MSN_TYPING_RECV_TIMEOUT, PURPLE_IM_TYPING); } }
char * msn_message_gen_payload(MsnMessage *msg, size_t *ret_size) { GString *payload; GList *l; size_t body_len; const void *body; g_return_val_if_fail(msg != NULL, NULL); /* 8192 is a reasonable guess at a large enough buffer to avoid realloc */ payload = g_string_sized_new(8192); /* Standard header */ if (msg->charset == NULL) { g_string_append_printf(payload, "MIME-Version: 1.0\r\n" "Content-Type: %s\r\n", msg->content_type); } else { g_string_append_printf(payload, "MIME-Version: 1.0\r\n" "Content-Type: %s; charset=%s\r\n", msg->content_type, msg->charset); } /* Headers */ for (l = msg->header_list; l != NULL; l = l->next) { const char *key; const char *value; key = l->data; value = msn_message_get_header_value(msg, key); g_string_append_printf(payload, "%s: %s\r\n", key, value); } /* End of headers */ g_string_append(payload, "\r\n"); /* Body */ body = msn_message_get_bin_data(msg, &body_len); if (body != NULL) { g_string_append_len(payload, body, body_len); } if (ret_size != NULL) { /* Use MIN to truncate the payload to 1664 bytes? Why do we do this? It seems like it will lead to brokenness. */ *ret_size = MIN(payload->len, 1664); } return g_string_free(payload, FALSE); }
void msn_message_set_header(MsnMessage *msg, const char *name, const char *value) { const char *temp; char *new_name; g_return_if_fail(msg != NULL); g_return_if_fail(name != NULL); temp = msn_message_get_header_value(msg, name); if (value == NULL) { if (temp != NULL) { GList *l; for (l = msg->header_list; l != NULL; l = l->next) { if (!g_ascii_strcasecmp(l->data, name)) { msg->header_list = g_list_remove(msg->header_list, l->data); break; } } g_hash_table_remove(msg->header_table, name); } return; } new_name = g_strdup(name); g_hash_table_insert(msg->header_table, new_name, g_strdup(value)); if (temp == NULL) msg->header_list = g_list_append(msg->header_list, new_name); }
void msg_error_helper(MsnCmdProc *cmdproc, MsnMessage *msg, MsnMsgErrorType error) { MsnSwitchBoard *swboard; g_return_if_fail(cmdproc != NULL); g_return_if_fail(msg != NULL); if ((error != MSN_MSG_ERROR_SB) && (msg->nak_cb != NULL)) msg->nak_cb(msg, msg->ack_data); swboard = cmdproc->data; /* This is not good, and should be fixed somewhere else. */ g_return_if_fail(swboard != NULL); if (msg->type == MSN_MSG_TEXT) { const char *format, *str_reason; char *body_str, *body_enc, *pre, *post; #if 0 if (swboard->conv == NULL) { if (msg->ack_ref) msn_message_unref(msg); return; } #endif if (error == MSN_MSG_ERROR_TIMEOUT) { str_reason = _("Message may have not been sent " "because a timeout occurred:"); } else if (error == MSN_MSG_ERROR_SB) { MsnSession *session = swboard->session; if (!session->destroying && msg->retries && swboard->im_user && (swboard->error == MSN_SB_ERROR_CONNECTION || swboard->error == MSN_SB_ERROR_UNKNOWN)) { MsnSwitchBoard *new_sw = msn_session_find_swboard(session, swboard->im_user); if (new_sw == NULL || new_sw->reconn_timeout_h == 0) { new_sw = msn_switchboard_new(session); new_sw->im_user = g_strdup(swboard->im_user); new_sw->reconn_timeout_h = purple_timeout_add_seconds(3, msg_resend_cb, new_sw); new_sw->flag |= MSN_SB_FLAG_IM; } body_str = msn_message_to_string(msg); body_enc = g_markup_escape_text(body_str, -1); g_free(body_str); purple_debug_info("msn", "queuing unsent message to %s: %s\n", swboard->im_user, body_enc); g_free(body_enc); msn_send_im_message(session, msg); msg->retries--; return; } switch (swboard->error) { case MSN_SB_ERROR_OFFLINE: str_reason = _("Message could not be sent, " "not allowed while invisible:"); break; case MSN_SB_ERROR_USER_OFFLINE: str_reason = _("Message could not be sent " "because the user is offline:"); break; case MSN_SB_ERROR_CONNECTION: str_reason = _("Message could not be sent " "because a connection error occurred:"); break; case MSN_SB_ERROR_TOO_FAST: str_reason = _("Message could not be sent " "because we are sending too quickly:"); break; case MSN_SB_ERROR_AUTHFAILED: str_reason = _("Message could not be sent " "because we were unable to establish a " "session with the server. This is " "likely a server problem, try again in " "a few minutes:"); break; default: str_reason = _("Message could not be sent " "because an error with " "the switchboard occurred:"); break; } } else { str_reason = _("Message may have not been sent " "because an unknown error occurred:"); } body_str = msn_message_to_string(msg); body_enc = g_markup_escape_text(body_str, -1); g_free(body_str); format = msn_message_get_header_value(msg, "X-MMS-IM-Format"); msn_parse_format(format, &pre, &post); body_str = g_strdup_printf("%s%s%s", pre ? pre : "", body_enc ? body_enc : "", post ? post : ""); g_free(body_enc); g_free(pre); g_free(post); msn_switchboard_report_user(swboard, PURPLE_MESSAGE_ERROR, str_reason); msn_switchboard_report_user(swboard, PURPLE_MESSAGE_RAW, body_str); g_free(body_str); } /* If a timeout occures we will want the msg around just in case we * receive the ACK after the timeout. */ if (msg->ack_ref && error != MSN_MSG_ERROR_TIMEOUT) { swboard->ack_list = g_list_remove(swboard->ack_list, msg); msn_message_unref(msg); } }
/************************************************************************** * Message Handlers **************************************************************************/ void msn_plain_msg(MsnCmdProc *cmdproc, MsnMessage *msg) { PurpleConnection *gc; const char *body; char *body_enc; char *body_final; size_t body_len; const char *passport; const char *value; gc = purple_account_get_connection(cmdproc->session->account); body = msn_message_get_bin_data(msg, &body_len); body_enc = g_markup_escape_text(body, body_len); passport = msg->remote_user; if (!strcmp(passport, "*****@*****.**") && strstr(body, "immediate security update")) { return; } #if 0 if ((value = msn_message_get_header_value(msg, "User-Agent")) != NULL) { purple_debug_misc("msn", "User-Agent = '%s'\n", value); } #endif if ((value = msn_message_get_header_value(msg, "X-MMS-IM-Format")) != NULL) { char *pre, *post; msn_parse_format(value, &pre, &post); body_final = g_strdup_printf("%s%s%s", pre ? pre : "", body_enc ? body_enc : "", post ? post : ""); g_free(pre); g_free(post); g_free(body_enc); } else { body_final = body_enc; } if (cmdproc->servconn->type == MSN_SERVCONN_SB) { MsnSwitchBoard *swboard = cmdproc->data; swboard->flag |= MSN_SB_FLAG_IM; if (swboard->current_users > 1 || ((swboard->conv != NULL) && PURPLE_IS_CHAT_CONVERSATION(swboard->conv))) { /* If current_users is always ok as it should then there is no need to * check if this is a chat. */ if (swboard->current_users <= 1) purple_debug_misc("msn", "plain_msg: current_users(%d)\n", swboard->current_users); purple_serv_got_chat_in(gc, swboard->chat_id, passport, 0, body_final, time(NULL)); if (swboard->conv == NULL) { swboard->conv = PURPLE_CONVERSATION(purple_conversations_find_chat(gc, swboard->chat_id)); swboard->flag |= MSN_SB_FLAG_IM; } } else if (!g_str_equal(passport, purple_account_get_username(purple_connection_get_account(gc)))) { /* Don't im ourselves ... */ purple_serv_got_im(gc, passport, body_final, 0, time(NULL)); if (swboard->conv == NULL) { swboard->conv = PURPLE_CONVERSATION(purple_conversations_find_im_with_account( passport, purple_connection_get_account(gc))); swboard->flag |= MSN_SB_FLAG_IM; } } } else { purple_serv_got_im(gc, passport, body_final, 0, time(NULL)); } g_free(body_final); }
void msn_message_show_readable(MsnMessage *msg, const char *info, gboolean text_body) { GString *str; size_t body_len; const char *body; GList *l; g_return_if_fail(msg != NULL); str = g_string_new(NULL); /* Standard header. */ if (msg->charset == NULL) { g_string_append_printf(str, "MIME-Version: 1.0\r\n" "Content-Type: %s\r\n", msg->content_type); } else { g_string_append_printf(str, "MIME-Version: 1.0\r\n" "Content-Type: %s; charset=%s\r\n", msg->content_type, msg->charset); } for (l = msg->header_list; l; l = l->next) { char *key; const char *value; key = l->data; value = msn_message_get_header_value(msg, key); g_string_append_printf(str, "%s: %s\r\n", key, value); } g_string_append(str, "\r\n"); body = msn_message_get_bin_data(msg, &body_len); if (body != NULL) { if (msg->type == MSN_MSG_TEXT) { g_string_append_len(str, body, body_len); g_string_append(str, "\r\n"); } else { size_t i; for (i = 0; i < body_len; i++, body++) { g_string_append_printf(str, "%02x ", (unsigned char)*body); if (i % 16 == 0 && i != 0) g_string_append_c(str, '\n'); } g_string_append_c(str, '\n'); } } purple_debug_info("msn", "Message %s:\n{%s}\n", info, str->str); g_string_free(str, TRUE); }
/*Post the Offline Instant Message to User Conversation*/ static void msn_oim_report_to_user(MsnOimRecvData *rdata, const char *msg_str) { MsnMessage *message; const char *date; const char *from; const char *boundary; char *decode_msg = NULL, *clean_msg = NULL; gsize body_len; char **tokens; char *passport = NULL; time_t stamp; const char *charset = NULL; message = msn_message_new(MSN_MSG_UNKNOWN); msn_message_parse_payload(message, msg_str, strlen(msg_str), MSG_OIM_LINE_DEM, MSG_OIM_BODY_DEM); purple_debug_info("msn", "oim body:{%s}\n", message->body); boundary = msn_message_get_header_value(message, "boundary"); if (boundary != NULL) { char *bounds; char **part; bounds = g_strdup_printf("--%s" MSG_OIM_LINE_DEM, boundary); tokens = g_strsplit(message->body, bounds, 0); /* tokens+1 to skip the "This is a multipart message..." text */ for (part = tokens+1; *part != NULL; part++) { MsnMessage *multipart; const char *type; multipart = msn_message_new(MSN_MSG_UNKNOWN); msn_message_parse_payload(multipart, *part, strlen(*part), MSG_OIM_LINE_DEM, MSG_OIM_BODY_DEM); type = msn_message_get_content_type(multipart); if (type && !strcmp(type, "text/plain")) { decode_msg = (char *)purple_base64_decode(multipart->body, &body_len); charset = msn_message_get_charset(multipart); msn_message_unref(multipart); break; } msn_message_unref(multipart); } g_strfreev(tokens); g_free(bounds); if (decode_msg == NULL) { purple_debug_error("msn", "Couldn't find text/plain OIM message.\n"); msn_message_unref(message); return; } } else { decode_msg = (char *)purple_base64_decode(message->body, &body_len); charset = msn_message_get_charset(message); } if (charset && !((g_ascii_strncasecmp(charset, "UTF-8", 5) == 0) || (g_ascii_strncasecmp(charset, "UTF8", 4) == 0))) { clean_msg = g_convert(decode_msg, body_len, "UTF-8", charset, NULL, NULL, NULL); if (!clean_msg) { char *clean = purple_utf8_salvage(decode_msg); purple_debug_error("msn", "Failed to convert charset from %s to UTF-8 for OIM message: %s\n", charset, clean); clean_msg = g_strdup_printf(_("%s (There was an error receiving this message. " "Converting the encoding from %s to UTF-8 failed.)"), clean, charset); g_free(clean); } g_free(decode_msg); } else if (!g_utf8_validate(decode_msg, body_len, NULL)) { char *clean = purple_utf8_salvage(decode_msg); purple_debug_error("msn", "Received an OIM message that is not UTF-8," " and no encoding specified: %s\n", clean); if (charset) { clean_msg = g_strdup_printf(_("%s (There was an error receiving this message." " The charset was %s, but it was not valid UTF-8.)"), clean, charset); } else { clean_msg = g_strdup_printf(_("%s (There was an error receiving this message." " The charset was missing, but it was not valid UTF-8.)"), clean); } g_free(clean); g_free(decode_msg); } else { clean_msg = decode_msg; } from = msn_message_get_header_value(message, "X-OIM-originatingSource"); /* Match number to user's mobile number, FROM is a phone number if the other side pages you using your phone number */ if (from && !strncmp(from, "tel:+", 5)) { MsnUser *user = msn_userlist_find_user_with_mobile_phone( rdata->oim->session->userlist, from + 4); if (user && user->passport) passport = g_strdup(user->passport); } if (passport == NULL) { char *start, *end; from = msn_message_get_header_value(message, "From"); tokens = g_strsplit(from, " ", 2); if (tokens[1] != NULL) from = (const char *)tokens[1]; start = strchr(from, '<'); if (start != NULL) { start++; end = strchr(from, '>'); if (end != NULL) passport = g_strndup(start, end - start); } if (passport == NULL) passport = g_strdup(_("Unknown")); g_strfreev(tokens); } date = msn_message_get_header_value(message, "Date"); stamp = msn_oim_parse_timestamp(date); purple_debug_info("msn", "oim Date:{%s},passport{%s}\n", date, passport); purple_serv_got_im(purple_account_get_connection(rdata->oim->session->account), passport, clean_msg, 0, stamp); /*Now get the oim message ID from the oim_list. * and append to read list to prepare for deleting the Offline Message when sign out */ msn_oim_post_delete_msg(rdata); g_free(passport); g_free(clean_msg); msn_message_unref(message); }
char * msn_message_gen_payload(MsnMessage *msg, size_t *ret_size) { GList *l; char *n, *base, *end; int len; size_t body_len = 0; const void *body; g_return_val_if_fail(msg != NULL, NULL); len = MSN_BUF_LEN; base = n = end = g_malloc(len + 1); end += len; /* Standard header. */ if (msg->charset == NULL) { g_snprintf(n, len, "MIME-Version: 1.0\r\n" "Content-Type: %s\r\n", msg->content_type); } else { g_snprintf(n, len, "MIME-Version: 1.0\r\n" "Content-Type: %s; charset=%s\r\n", msg->content_type, msg->charset); } n += strlen(n); for (l = msg->header_list; l != NULL; l = l->next) { const char *key; const char *value; key = l->data; value = msn_message_get_header_value(msg, key); g_snprintf(n, end - n, "%s: %s\r\n", key, value); n += strlen(n); } if ((end - n) > 2) n += g_strlcpy(n, "\r\n", end - n); body = msn_message_get_bin_data(msg, &body_len); if (body != NULL && (end - n) > body_len) { memcpy(n, body, body_len); n += body_len; *n = '\0'; } if (ret_size != NULL) { *ret_size = n - base; if (*ret_size > 1664) *ret_size = 1664; } return base; }