diff options
Diffstat (limited to 'protocols/FacebookRM/src/json.cpp')
-rw-r--r-- | protocols/FacebookRM/src/json.cpp | 807 |
1 files changed, 394 insertions, 413 deletions
diff --git a/protocols/FacebookRM/src/json.cpp b/protocols/FacebookRM/src/json.cpp index 32909c95b4..d6b7bfb8cd 100644 --- a/protocols/FacebookRM/src/json.cpp +++ b/protocols/FacebookRM/src/json.cpp @@ -21,197 +21,157 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. */
#include "common.h"
-#include "JSON_CAJUN/reader.h"
-#include "JSON_CAJUN/writer.h"
-#include "JSON_CAJUN/elements.h"
int facebook_json_parser::parse_buddy_list(void* data, List::List< facebook_user >* buddy_list)
{
- using namespace json;
-
- try
- {
- facebook_user* current = NULL;
- std::string buddyData = static_cast< std::string* >(data)->substr(9);
- std::istringstream sDocument(buddyData);
- Object objDocument;
- Reader::Read(objDocument, sDocument);
-
- const Object& objRoot = objDocument;
-/* const Array& wasAvailableIDs = objRoot["payload"]["buddy_list"]["wasAvailableIDs"];
-
- for (Array::const_iterator itWasAvailable(wasAvailableIDs.Begin());
- itWasAvailable != wasAvailableIDs.End(); ++itWasAvailable)
- {
- const Number& member = *itWasAvailable;
- char was_id[32];
- lltoa(member.Value(), was_id, 10);
-
- current = buddy_list->find(std::string(was_id));
- if (current != NULL)
- current->status_id = ID_STATUS_OFFLINE;
- }*/ // Facebook removed support for "wasAvailableIDs"
+ facebook_user* current = NULL;
+ std::string jsonData = static_cast< std::string* >(data)->substr(9);
- // Set all contacts in map to offline
- for (List::Item< facebook_user >* i = buddy_list->begin(); i != NULL; i = i->next) {
- i->data->status_id = ID_STATUS_OFFLINE;
- }
+ JSONNODE *root = json_parse(jsonData.c_str());
+ if (root == NULL)
+ return EXIT_FAILURE;
- // Load last active times
- const Object& lastActive = objRoot["payload"]["buddy_list"]["last_active_times"];
- for (Object::const_iterator itLastActive(lastActive.Begin()); itLastActive != lastActive.End(); ++itLastActive)
- {
- const Object::Member& member = *itLastActive;
+ JSONNODE *payload = json_get(root, "payload");
+ if (payload == NULL)
+ return EXIT_FAILURE;
- current = buddy_list->find(member.name);
+ JSONNODE *list = json_get(payload, "buddy_list");
+ if (list == NULL)
+ return EXIT_FAILURE;
+
+ // Set all contacts in map to offline
+ for (List::Item< facebook_user >* i = buddy_list->begin(); i != NULL; i = i->next) {
+ i->data->status_id = ID_STATUS_OFFLINE;
+ }
+
+ // Load last active times
+ JSONNODE *lastActive = json_get(list, "last_active_times");
+ if (lastActive != NULL) {
+ for (unsigned int i = 0; i < json_size(lastActive); i++) {
+ JSONNODE *it = json_at(lastActive, i);
+ char *id = json_name(it);
+
+ current = buddy_list->find(id);
if (current == NULL) {
- buddy_list->insert(std::make_pair(member.name, new facebook_user()));
- current = buddy_list->find(member.name);
- current->user_id = member.name;
+ buddy_list->insert(std::make_pair(id, new facebook_user()));
+ current = buddy_list->find(id);
+ current->user_id = id;
}
- const Number& timestamp = member.element;
- current->last_active = timestamp.Value();
+ current->last_active = json_as_int(it);
}
-
- // Find mobile friends
- const Array& mobileFriends = objRoot["payload"]["buddy_list"]["mobile_friends"];
- for (Array::const_iterator buddy(mobileFriends.Begin()); buddy != mobileFriends.End(); ++buddy) {
- const Number& member = *buddy;
- char was_id[32];
- lltoa(member.Value(), was_id, 10);
-
- std::string id = was_id;
- if (!id.empty()) {
+ }
+
+ // Find mobile friends
+ JSONNODE *mobileFriends = json_get(list, "mobile_friends");
+ if (mobileFriends != NULL) {
+ for (unsigned int i = 0; i < json_size(mobileFriends); i++) {
+ JSONNODE *it = json_at(mobileFriends, i);
+ char *id = json_name(it);
+
+ current = buddy_list->find(id);
+ if (current == NULL) {
+ buddy_list->insert(std::make_pair(id, new facebook_user()));
current = buddy_list->find(id);
-
- if (current == NULL) {
- buddy_list->insert(std::make_pair(id, new facebook_user()));
- current = buddy_list->find(id);
- current->user_id = id;
- }
-
- current->status_id = ID_STATUS_ONTHEPHONE;
+ current->user_id = id;
}
- }
- // Find now awailable contacts
- const Object& nowAvailableList = objRoot["payload"]["buddy_list"]["nowAvailableList"];
- for (Object::const_iterator itAvailable(nowAvailableList.Begin());
- itAvailable != nowAvailableList.End(); ++itAvailable)
- {
- const Object::Member& member = *itAvailable;
- const Object& objMember = member.element;
- const Boolean idle = objMember["i"]; // In new version of Facebook "i" means "offline"
+ current->status_id = ID_STATUS_ONTHEPHONE;
+ }
+ }
- current = buddy_list->find(member.name);
+ // Find now awailable contacts
+ JSONNODE *nowAvailable = json_get(list, "nowAvailableList");
+ if (nowAvailable != NULL) {
+ for (unsigned int i = 0; i < json_size(nowAvailable); i++) {
+ JSONNODE *it = json_at(nowAvailable, i);
+ char *id = json_name(it);
+
+ current = buddy_list->find(id);
if (current == NULL) {
- if (idle) continue; // Just little optimalization
-
- buddy_list->insert(std::make_pair(member.name, new facebook_user()));
- current = buddy_list->find(member.name);
- current->user_id = current->real_name = member.name;
+ buddy_list->insert(std::make_pair(id, new facebook_user()));
+ current = buddy_list->find(id);
+ current->user_id = id;
}
- current->status_id = (idle ? ID_STATUS_OFFLINE : ID_STATUS_ONLINE);
+ current->status_id = ID_STATUS_ONLINE;
+
+ // In new version of Facebook "i" means "offline"
+ JSONNODE *idle = json_get(it, "i");
+ if (idle != NULL && json_as_bool(idle))
+ current->status_id = ID_STATUS_OFFLINE;
}
+ }
- // Get aditional informations about contacts (if available)
- const Object& userInfosList = objRoot["payload"]["buddy_list"]["userInfos"];
- for (Object::const_iterator itUserInfo(userInfosList.Begin());
- itUserInfo != userInfosList.End(); ++itUserInfo)
- {
- const Object::Member& member = *itUserInfo;
-
- current = buddy_list->find(member.name);
+ // Get aditional informations about contacts (if available)
+ JSONNODE *userInfos = json_get(list, "userInfos");
+ if (userInfos != NULL) {
+ for (unsigned int i = 0; i < json_size(userInfos); i++) {
+ JSONNODE *it = json_at(userInfos, i);
+ char *id = json_name(it);
+
+ current = buddy_list->find(id);
if (current == NULL)
continue;
- const Object& objMember = member.element;
- const String& realName = objMember["name"];
- const String& imageUrl = objMember["thumbSrc"];
+ JSONNODE *name = json_get(it, "name");
+ JSONNODE *thumbSrc = json_get(it, "thumbSrc");
- current->real_name = utils::text::slashu_to_utf8(
- utils::text::special_expressions_decode(realName.Value()));
- current->image_url = utils::text::slashu_to_utf8(
- utils::text::special_expressions_decode(imageUrl.Value()));
+ if (name != NULL)
+ current->real_name = utils::text::slashu_to_utf8(utils::text::special_expressions_decode(json_as_string(name)));
+ if (thumbSrc != NULL)
+ current->image_url = utils::text::slashu_to_utf8(utils::text::special_expressions_decode(json_as_string(thumbSrc)));
}
-
- }
- catch (Reader::ParseException& e)
- {
- proto->Log("!!!!! Caught json::ParseException: %s", e.what());
- proto->Log(" Line/offset: %d/%d", e.m_locTokenBegin.m_nLine + 1, e.m_locTokenBegin.m_nLineOffset + 1);
- }
- catch (const Exception& e)
- {
- proto->Log("!!!!! Caught json::Exception: %s", e.what());
- }
- catch (const std::exception& e)
- {
- proto->Log("!!!!! Caught std::exception: %s", e.what());
}
+ json_delete(root);
+
return EXIT_SUCCESS;
}
int facebook_json_parser::parse_friends(void* data, std::map< std::string, facebook_user* >* friends)
{
- using namespace json;
-
- try
- {
- std::string buddyData = static_cast< std::string* >(data)->substr(9);
- std::istringstream sDocument(buddyData);
- Object objDocument;
- Reader::Read(objDocument, sDocument);
-
- const Object& objRoot = objDocument;
- const Object& payload = objRoot["payload"];
-
- for (Object::const_iterator payload_item(payload.Begin()); payload_item != payload.End(); ++payload_item)
- {
- const Object::Member& member = *payload_item;
-
- const Object& objMember = member.element;
-
- const String& realName = objMember["name"];
- const String& imageUrl = objMember["thumbSrc"];
- //const String& vanity = objMember["vanity"];
- //const String& uri = objMember["uri"];
- const Number& gender = objMember["gender"];
- //const Boolean& isFriend = objMember["is_friend"];
- //const String& type = objMember["type"]; // "friend" = existing classic contact, "user" = contact with disabled/deleted account
-
- facebook_user *fbu = new facebook_user();
-
- fbu->user_id = member.name;
- fbu->real_name = utils::text::slashu_to_utf8(
- utils::text::special_expressions_decode(realName.Value()));
- fbu->image_url = utils::text::slashu_to_utf8(
- utils::text::special_expressions_decode(imageUrl.Value()));
-
- if (gender.Value() == 1) {
- fbu->gender = 70; // female
- } else if (gender.Value() == 2) {
- fbu->gender = 77; // male
+ std::string jsonData = static_cast< std::string* >(data)->substr(9);
+
+ JSONNODE *root = json_parse(jsonData.c_str());
+ if (root == NULL)
+ return EXIT_FAILURE;
+
+ JSONNODE *payload = json_get(root, "payload");
+ if (payload == NULL)
+ return EXIT_FAILURE;
+
+ for (unsigned int i = 0; i < json_size(payload); i++) {
+ JSONNODE *it = json_at(payload, i);
+ char *id = json_name(it);
+
+ JSONNODE *name = json_get(it, "name");
+ JSONNODE *thumbSrc = json_get(it, "thumbSrc");
+ JSONNODE *gender = json_get(it, "gender");
+ //JSONNODE *vanity = json_get(it, "vanity"); // username
+ //JSONNODE *uri = json_get(it, "uri"); // profile url
+ //JSONNODE *is_friend = json_get(it, "is_friend"); // e.g. "True"
+ //JSONNODE *type = json_get(it, "type"); // e.g. "friend" (classic contact) or "user" (disabled/deleted account)
+
+ facebook_user *fbu = new facebook_user();
+
+ fbu->user_id = id;
+ if (name)
+ fbu->real_name = utils::text::slashu_to_utf8(utils::text::special_expressions_decode(json_as_string(name)));
+ if (thumbSrc)
+ fbu->image_url = utils::text::slashu_to_utf8(utils::text::special_expressions_decode(json_as_string(thumbSrc)));
+
+ if (gender)
+ switch (json_as_int(gender)) {
+ case 1: // female
+ fbu->gender = 70;
+ break;
+ case 2: // male
+ fbu-> gender = 77;
+ break;
}
- friends->insert(std::make_pair(member.name, fbu));
- }
- }
- catch (Reader::ParseException& e)
- {
- proto->Log("!!!!! Caught json::ParseException: %s", e.what());
- proto->Log(" Line/offset: %d/%d", e.m_locTokenBegin.m_nLine + 1, e.m_locTokenBegin.m_nLineOffset + 1);
- }
- catch (const Exception& e)
- {
- proto->Log("!!!!! Caught json::Exception: %s", e.what());
- }
- catch (const std::exception& e)
- {
- proto->Log("!!!!! Caught std::exception: %s", e.what());
+ friends->insert(std::make_pair(id, fbu));
}
return EXIT_SUCCESS;
@@ -220,54 +180,41 @@ int facebook_json_parser::parse_friends(void* data, std::map< std::string, faceb int facebook_json_parser::parse_notifications(void *data, std::vector< facebook_notification* > *notifications)
{
- using namespace json;
+ std::string jsonData = static_cast< std::string* >(data)->substr(9);
+
+ JSONNODE *root = json_parse(jsonData.c_str());
+ if (root == NULL)
+ return EXIT_FAILURE;
- try
- {
- std::string notificationsData = static_cast< std::string* >(data)->substr(9);
- std::istringstream sDocument(notificationsData);
- Object objDocument;
- Reader::Read(objDocument, sDocument);
+ JSONNODE *payload = json_get(root, "payload");
+ if (payload == NULL)
+ return EXIT_FAILURE;
- const Object& objRoot = objDocument;
- const Object& payload = objRoot["payload"]["notifications"];
+ JSONNODE *list = json_get(payload, "notifications");
+ if (list == NULL)
+ return EXIT_FAILURE;
- for (Object::const_iterator payload_item(payload.Begin()); payload_item != payload.End(); ++payload_item)
- {
- const Object::Member& member = *payload_item;
-
- const Object& objMember = member.element;
- const String& content = objMember["markup"];
- const Number& unread = objMember["unread"];
-
- if (unread.Value() == 0) // ignore old notifications
- continue;
-
- std::string text = utils::text::slashu_to_utf8(
- utils::text::special_expressions_decode(content.Value()));
+ for (unsigned int i = 0; i < json_size(list); i++) {
+ JSONNODE *it = json_at(list, i);
+ char *id = json_name(it);
- facebook_notification* notification = new facebook_notification();
-
- notification->text = utils::text::remove_html(utils::text::source_get_value(&text, 1, "<abbr"));
- notification->link = utils::text::source_get_value(&text, 3, "<a ", "href=\"", "\"");
- notification->id = member.name;
+ JSONNODE *markup = json_get(it, "markup");
+ JSONNODE *unread = json_get(it, "unread");
+ //JSONNODE *time = json_get(it, "time");
- notifications->push_back(notification);
- }
+ // Ignore empty and old notifications
+ if (markup == NULL || unread == NULL || json_as_int(unread) == 0)
+ continue;
- }
- catch (Reader::ParseException& e)
- {
- proto->Log("!!!!! Caught json::ParseException: %s", e.what());
- proto->Log(" Line/offset: %d/%d", e.m_locTokenBegin.m_nLine + 1, e.m_locTokenBegin.m_nLineOffset + 1);
- }
- catch (const Exception& e)
- {
- proto->Log("!!!!! Caught json::Exception: %s", e.what());
- }
- catch (const std::exception& e)
- {
- proto->Log("!!!!! Caught std::exception: %s", e.what());
+ std::string text = utils::text::slashu_to_utf8(utils::text::special_expressions_decode(json_as_string(markup)));
+
+ facebook_notification* notification = new facebook_notification();
+
+ notification->id = id;
+ notification->link = utils::text::source_get_value(&text, 3, "<a ", "href=\"", "\"");
+ notification->text = utils::text::remove_html(utils::text::source_get_value(&text, 1, "<abbr"));
+
+ notifications->push_back(notification);
}
return EXIT_SUCCESS;
@@ -290,265 +237,299 @@ bool ignore_duplicits(FacebookProto *proto, std::string mid, std::string text) { int facebook_json_parser::parse_messages(void* data, std::vector< facebook_message* >* messages, std::vector< facebook_notification* >* notifications)
{
- using namespace json;
+ std::string jsonData = static_cast< std::string* >(data)->substr(9);
+
+ JSONNODE *root = json_parse(jsonData.c_str());
+ if (root == NULL)
+ return EXIT_FAILURE;
- try
- {
- std::string messageData = static_cast< std::string* >(data)->substr(9);
- std::istringstream sDocument(messageData);
- Object objDocument;
- Reader::Read(objDocument, sDocument);
+ JSONNODE *ms = json_get(root, "ms");
+ if (ms == NULL)
+ return EXIT_FAILURE;
- const Object& objRoot = objDocument;
- const Array& messagesArray = objRoot["ms"];
+ for (unsigned int i = 0; i < json_size(ms); i++) {
+ JSONNODE *it = json_at(ms, i);
+
+ JSONNODE *type = json_get(it, "type");
+ if (type == NULL)
+ continue;
- for (Array::const_iterator itMessage(messagesArray.Begin()); itMessage != messagesArray.End(); ++itMessage)
- {
- const Object& objMember = *itMessage;
+ std::string t = json_as_string(type);
+ if (t == "msg" || t == "offline_msg") {
+ // direct message
+
+ JSONNODE *from = json_get(it, "from");
+ if (from == NULL)
+ continue;
- const String& type = objMember["type"];
+ char *from_id = json_as_string(from);
- if (type.Value() == "msg" || type.Value() == "offline_msg") // direct message
- {
- const Number& from = objMember["from"];
- char was_id[32];
- lltoa(from.Value(), was_id, 10);
-
- const Object& messageContent = objMember["msg"];
- const String& text = messageContent["text"];
- const String& message_id = messageContent["messageId"];
- //"tab_type":"friend", objMember["tab_type"]
-
- const Number& time_sent = messageContent["time"];
-
- // ignore duplicits or messages sent from miranda
- if (ignore_duplicits(proto, message_id.Value(), text.Value()))
+ JSONNODE *msg = json_get(it, "msg");
+ if (msg == NULL)
+ continue;
+
+ JSONNODE *text = json_get(msg, "text");
+ JSONNODE *messageId = json_get(msg, "messageId");
+ JSONNODE *time = json_get(it, "time");
+ // JSONNODE *tab_type = json_get(it, "tab_type"); // e.g. "friend"
+
+ if (text == NULL || messageId == NULL)
+ continue;
+
+ std::string message_id = json_as_string(messageId);
+ std::string message_text = json_as_string(text);
+
+ // ignore duplicits or messages sent from miranda
+ if (ignore_duplicits(proto, message_id, message_text))
+ continue;
+
+ message_text = utils::text::trim(utils::text::special_expressions_decode(utils::text::slashu_to_utf8(message_text)), true);
+ if (message_text.empty())
+ continue;
+
+ JSONNODE *truncated = json_get(msg, "truncated");
+ if (truncated != NULL && json_as_int(truncated) == 1) {
+ // If we got truncated message, we can ignore it, because we should get it again as "messaging" type
+ std::string msg = "????? We got truncated message so we ignore it\n";
+ msg += utils::text::special_expressions_decode(utils::text::slashu_to_utf8(message_text));
+ proto->Log(msg.c_str());
+ } else if (from_id == proto->facy.self_.user_id) {
+ // Outgoing message
+ JSONNODE *to = json_get(it, "to");
+ if (to == NULL)
continue;
- std::string message_text = utils::text::trim(utils::text::special_expressions_decode(utils::text::slashu_to_utf8(text.Value())), true);
- if (message_text.empty())
+ // TODO: put also outgoing messages into messages array and process it elsewhere
+ HANDLE hContact = proto->ContactIDToHContact(json_as_string(to));
+ if (!hContact) // TODO: add this contact?
continue;
- if (was_id == proto->facy.self_.user_id) {
- const Number& to = objMember["to"];
- char to_id[32];
- lltoa(to.Value(), to_id, 10);
+ DBEVENTINFO dbei = {0};
+ dbei.cbSize = sizeof(dbei);
+ dbei.eventType = EVENTTYPE_MESSAGE;
+ dbei.flags = DBEF_SENT | DBEF_UTF;
+ dbei.szModule = proto->m_szModuleName;
+
+ bool local_time = proto->getByte(FACEBOOK_KEY_LOCAL_TIMESTAMP, 0) != 0;
+ dbei.timestamp = local_time || time == NULL ? ::time(NULL) : utils::time::fix_timestamp(json_as_int(time));
+
+ dbei.cbBlob = (DWORD)message_text.length() + 1;
+ dbei.pBlob = (PBYTE)message_text.c_str();
+ db_event_add(hContact, &dbei);
+
+ continue;
+ } else {
+ // Incomming message
+ facebook_message* message = new facebook_message();
+ message->message_text = message_text;
+ message->time = utils::time::fix_timestamp(json_as_int(time));
+ message->user_id = from_id;
+ message->message_id = message_id;
+
+ messages->push_back(message);
+ }
- HANDLE hContact = proto->ContactIDToHContact(to_id);
- if (!hContact)
- continue;
+ } else if (t == "messaging") {
+ // messages
- DBEVENTINFO dbei = {0};
- dbei.cbSize = sizeof(dbei);
- dbei.eventType = EVENTTYPE_MESSAGE;
- dbei.flags = DBEF_SENT | DBEF_UTF;
- dbei.szModule = proto->m_szModuleName;
+ JSONNODE *type = json_get(it, "event");
+ if (type == NULL)
+ continue;
- bool local_time = proto->getByte(FACEBOOK_KEY_LOCAL_TIMESTAMP, 0) != 0;
- dbei.timestamp = local_time ? ::time(NULL) : utils::time::fix_timestamp(time_sent.Value());
+ std::string t = json_as_string(type);
- dbei.cbBlob = (DWORD)message_text.length() + 1;
- dbei.pBlob = (PBYTE)message_text.c_str();
- db_event_add(hContact, &dbei);
+ if (t == "read_receipt") {
+ // user read message
+ JSONNODE *reader = json_get(it, "reader");
+ JSONNODE *time = json_get(it, "time");
+ if (reader == NULL || time == NULL)
continue;
- }
- if ((messageContent.Find("truncated") != messageContent.End())
- && (((const Number &)messageContent["truncated"]).Value() == 1)) {
- // If we got truncated message, we can ignore it, because we should get it again as "messaging" type
- std::string msg = "????? We got truncated message so we ignore it\n";
- msg += utils::text::special_expressions_decode(utils::text::slashu_to_utf8(text.Value()));
- proto->Log(msg.c_str());
- } else {
- facebook_message* message = new facebook_message();
- message->message_text = message_text;
- message->time = utils::time::fix_timestamp(time_sent.Value());
- message->user_id = was_id;
- message->message_id = message_id;
-
- messages->push_back(message);
- }
- }
- else if (type.Value() == "messaging")
- {
- const String& type = objMember["event"];
-
- if (type.Value() == "read_receipt") {
- // user read message
- const Number& reader = objMember["reader"];
- const Number& time = objMember["time"];
-
- char user_id[32];
- lltoa(reader.Value(), user_id, 10);
-
- // TODO: add check for chat contacts
- HANDLE hContact = proto->ContactIDToHContact(user_id);
- if (hContact) {
- TCHAR ttime[64], tstr[100];
- _tcsftime(ttime, SIZEOF(ttime), _T("%X"), utils::conversion::fbtime_to_timeinfo(time.Value()));
- mir_sntprintf(tstr, SIZEOF(tstr), TranslateT("Message read: %s"), ttime);
-
- CallService(MS_MSG_SETSTATUSTEXT, (WPARAM)hContact, (LPARAM)tstr);
- }
-
- } else if (type.Value() == "deliver") {
- // inbox message (multiuser or direct)
- const Object& messageContent = objMember["message"];
-
- const Number& sender_fbid = messageContent["sender_fbid"];
- const String& sender_name = messageContent["sender_name"];
- const String& text = messageContent["body"];
- const String& tid = messageContent["tid"];
- const String& mid = messageContent["mid"];
- const Number& time_sent = messageContent["timestamp"];
-
- char was_id[32];
- lltoa(sender_fbid.Value(), was_id, 10);
-
- // Ignore messages from myself
- if (was_id == proto->facy.self_.user_id)
- continue;
-
- // Ignore duplicits or messages sent from miranda
- if (ignore_duplicits(proto, mid.Value(), text.Value()))
- continue;
-
- std::string message_text = utils::text::trim(utils::text::special_expressions_decode(utils::text::slashu_to_utf8(text.Value())), true);
- if (message_text.empty())
- continue;
-
- facebook_message* message = new facebook_message();
- message->message_text = message_text;
- message->sender_name = utils::text::special_expressions_decode(utils::text::slashu_to_utf8(sender_name.Value()));
- message->time = utils::time::fix_timestamp(time_sent.Value());
- message->user_id = was_id; // TODO: Check if we have contact with this ID in friendlist and otherwise do something different?
- message->message_id = mid.Value();
-
- messages->push_back(message);
+ // TODO: add check for chat contacts
+ HANDLE hContact = proto->ContactIDToHContact(json_as_string(reader));
+ if (hContact) {
+ TCHAR ttime[64], tstr[100];
+ _tcsftime(ttime, SIZEOF(ttime), _T("%X"), utils::conversion::fbtime_to_timeinfo(json_as_int(time)));
+ mir_sntprintf(tstr, SIZEOF(tstr), TranslateT("Message read: %s"), ttime);
+
+ CallService(MS_MSG_SETSTATUSTEXT, (WPARAM)hContact, (LPARAM)tstr);
}
- }
- else if (type.Value() == "thread_msg") // multiuser message
- {
- const String& from_name = objMember["from_name"];
- const String& to_name = objMember["to_name"]["__html"];
- const String& to_id = objMember["to"];
+ } else if (t == "deliver") {
+ // inbox message (multiuser or direct)
- const Number& from = objMember["from"];
- char was_id[32];
- lltoa(from.Value(), was_id, 10);
+ JSONNODE *msg = json_get(it, "message");
- const Object& messageContent = objMember["msg"];
- const String& text = messageContent["text"];
- const String& mid = messageContent["messageId"];
+ JSONNODE *sender_fbid = json_get(msg, "sender_fbid");
+ JSONNODE *sender_name = json_get(msg, "sender_name");
+ JSONNODE *body = json_get(msg, "body");
+ JSONNODE *tid = json_get(msg, "tid");
+ JSONNODE *mid = json_get(msg, "mid");
+ JSONNODE *timestamp = json_get(msg, "timestamp");
+
+ if (sender_fbid == NULL || body == NULL || mid == NULL)
+ continue;
+
+ std::string id = json_as_string(sender_fbid);
+ std::string message_id = json_as_string(mid);
+ std::string message_text = json_as_string(body);
// Ignore messages from myself
- if (was_id == proto->facy.self_.user_id)
+ if (id == proto->facy.self_.user_id)
continue;
-
+
// Ignore duplicits or messages sent from miranda
- if (ignore_duplicits(proto, mid.Value(), text.Value()))
+ if (body == NULL || ignore_duplicits(proto, message_id, message_text))
continue;
- std::string message_text = utils::text::trim(utils::text::special_expressions_decode(utils::text::slashu_to_utf8(text.Value())), true);
+ message_text = utils::text::trim(utils::text::special_expressions_decode(utils::text::slashu_to_utf8(message_text)), true);
if (message_text.empty())
continue;
- std::string title = utils::text::special_expressions_decode(utils::text::slashu_to_utf8(to_name.Value()));
- std::string url = "/?action=read&sk=inbox&page&query&tid=" + to_id.Value();
- std::string popup_text = utils::text::special_expressions_decode(utils::text::slashu_to_utf8(from_name.Value()));
- popup_text += ": " + message_text;
+ facebook_message* message = new facebook_message();
+ message->message_text = message_text;
+ message->sender_name = utils::text::special_expressions_decode(utils::text::slashu_to_utf8(id));
+ message->time = utils::time::fix_timestamp(json_as_int(timestamp));
+ message->user_id = id; // TODO: Check if we have contact with this ID in friendlist and otherwise do something different?
+ message->message_id = message_id;
- proto->Log(" Got multichat message");
-
- TCHAR* szTitle = mir_utf8decodeT(title.c_str());
- TCHAR* szText = mir_utf8decodeT(popup_text.c_str());
- proto->NotifyEvent(szTitle, szText, NULL, FACEBOOK_EVENT_OTHER, &url);
- mir_free(szTitle);
- mir_free(szText);
+ messages->push_back(message);
}
- else if (type.Value() == "notification_json") // event notification
- {
- if (!proto->getByte(FACEBOOK_KEY_EVENT_NOTIFICATIONS_ENABLE, DEFAULT_EVENT_NOTIFICATIONS_ENABLE))
- continue;
+ } else if (t == "thread_msg") {
+ // multiuser message
+
+ JSONNODE *from_name = json_get(it, "from_name");
+ JSONNODE *to_name_ = json_get(it, "to_name");
+ if (to_name_ == NULL)
+ continue;
+ JSONNODE *to_name = json_get(to_name_, "__html");
+ JSONNODE *to_id = json_get(it, "to");
+ JSONNODE *from_id = json_get(it, "from");
+
+ JSONNODE *msg = json_get(it, "msg");
+ JSONNODE *text = json_get(msg, "text");
+ JSONNODE *messageId = json_get(msg, "messageId");
+
+ if (from_id == NULL || text == NULL || messageId == NULL)
+ continue;
+
+ std::string id = json_as_string(from_id);
+ std::string message_id = json_as_string(messageId);
+ std::string message_text = json_as_string(text);
+
+ // Ignore messages from myself
+ if (id == proto->facy.self_.user_id)
+ continue;
+
+ // Ignore duplicits or messages sent from miranda
+ if (ignore_duplicits(proto, message_id, message_text))
+ continue;
+
+ message_text = utils::text::trim(utils::text::special_expressions_decode(utils::text::slashu_to_utf8(message_text)), true);
+ if (message_text.empty())
+ continue;
- const Array& notificationsArray = objMember["nodes"];
+ std::string title = utils::text::special_expressions_decode(utils::text::slashu_to_utf8(json_as_string(to_name)));
+ std::string url = "/?action=read&sk=inbox&page&query&tid=" + id;
+ std::string popup_text = utils::text::special_expressions_decode(utils::text::slashu_to_utf8(json_as_string(from_name)));
+ popup_text += ": " + message_text;
- for (Array::const_iterator itNotification(notificationsArray.Begin()); itNotification != notificationsArray.End(); ++itNotification)
- {
- const Object& objNotification = *itNotification;
+ proto->Log(" Got multichat message");
+
+ TCHAR* szTitle = mir_utf8decodeT(title.c_str());
+ TCHAR* szText = mir_utf8decodeT(popup_text.c_str());
+ proto->NotifyEvent(szTitle, szText, NULL, FACEBOOK_EVENT_OTHER, &url);
+ mir_free(szTitle);
+ mir_free(szText);
+ } else if (t == "notification_json") {
+ // event notification
+
+ if (!proto->getByte(FACEBOOK_KEY_EVENT_NOTIFICATIONS_ENABLE, DEFAULT_EVENT_NOTIFICATIONS_ENABLE))
+ continue;
- //const String& text = objNotification["title"]["text"];
- const String& text = objNotification["unaggregatedTitle"]["text"];
- const String& link = objNotification["url"];
- const String& id = objNotification["alert_id"];
+ JSONNODE *nodes = json_get(it, "nodes");
+ for (unsigned int i = 0; i < json_size(nodes); i++) {
+ JSONNODE *itNodes = json_at(nodes, i);
- const Number& time_sent = objNotification["timestamp"]["time"];
- if (time_sent.Value() > proto->facy.last_notification_time_) // Check against duplicit notifications
- {
- proto->facy.last_notification_time_ = time_sent.Value();
+ //JSONNODE *text = json_get(itNodes, "title/text");
+ JSONNODE *text_ = json_get(itNodes, "unaggregatedTitle");
+ if (text_ == NULL)
+ continue;
+ JSONNODE *text = json_get(text_, "text");
+ JSONNODE *url = json_get(itNodes, "url");
+ JSONNODE *alert_id = json_get(itNodes, "alert_id");
+
+ JSONNODE *time_ = json_get(it, "timestamp");
+ if (time_ == NULL)
+ continue;
+ JSONNODE *time = json_get(time_, "time");
+ if (time == NULL || text == NULL || url == NULL || alert_id == NULL)
+ continue;
- facebook_notification* notification = new facebook_notification();
- notification->text = utils::text::slashu_to_utf8(text.Value());
- notification->link = utils::text::special_expressions_decode(link.Value());
-
- std::string::size_type pos = id.Value().find(":");
- notification->id = (pos != std::string::npos) ? id.Value().substr(pos+1) : id.Value();
+ unsigned long timestamp = json_as_int(time);
+ if (timestamp > proto->facy.last_notification_time_) {
+ // Only new notifications
+ proto->facy.last_notification_time_ = timestamp;
- notifications->push_back(notification);
- }
+ facebook_notification* notification = new facebook_notification();
+ notification->text = utils::text::slashu_to_utf8(json_as_string(text));
+ notification->link = utils::text::special_expressions_decode(json_as_string(url));
+ notification->id = json_as_string(alert_id);
+
+ std::string::size_type pos = notification->id.find(":");
+ if (pos != std::string::npos)
+ notification->id = notification->id.substr(pos+1);
+
+ notifications->push_back(notification);
}
}
- else if (type.Value() == "typ") // chat typing notification
- {
- const Number& from = objMember["from"];
- char user_id[32];
- lltoa(from.Value(), user_id, 10);
+ } else if (t == "typ") {
+ // chat typing notification
+
+ JSONNODE *from = json_get(it, "from");
+ if (from == NULL)
+ continue;
- facebook_user fbu;
- fbu.user_id = user_id;
+ facebook_user fbu;
+ fbu.user_id = json_as_string(from);
- HANDLE hContact = proto->AddToContactList(&fbu, CONTACT_FRIEND);
+ HANDLE hContact = proto->AddToContactList(&fbu, CONTACT_FRIEND);
- if (proto->getWord(hContact, "Status", 0) == ID_STATUS_OFFLINE)
- proto->setWord(hContact, "Status", ID_STATUS_ONLINE);
-
- const Number& state = objMember["st"];
- if (state.Value() == 1)
- CallService(MS_PROTO_CONTACTISTYPING, (WPARAM)hContact, (LPARAM)60);
- else
- CallService(MS_PROTO_CONTACTISTYPING, (WPARAM)hContact, (LPARAM)PROTOTYPE_CONTACTTYPING_OFF);
- }
- else if (type.Value() == "privacy_changed")
- {
- const String& event_type = objMember["event"];
- const Object& event_data = objMember["data"];
-
- if (event_type.Value() == "visibility_update")
- { // change of chat status
- const Boolean visibility = event_data["visibility"];
- proto->Log(" Requested chat switch to %s", visibility ? "Online" : "Offline");
- proto->SetStatus(visibility ? ID_STATUS_ONLINE : ID_STATUS_INVISIBLE);
- }
- }
+ if (proto->getWord(hContact, "Status", 0) == ID_STATUS_OFFLINE)
+ proto->setWord(hContact, "Status", ID_STATUS_ONLINE);
+
+ JSONNODE *st = json_get(it, "st");
+ if (json_as_int(st) == 1)
+ CallService(MS_PROTO_CONTACTISTYPING, (WPARAM)hContact, (LPARAM)60);
else
+ CallService(MS_PROTO_CONTACTISTYPING, (WPARAM)hContact, (LPARAM)PROTOTYPE_CONTACTTYPING_OFF);
+ } else if (t == "privacy_changed") {
+ // settings changed
+
+ JSONNODE *event_type = json_get(it, "event");
+ JSONNODE *event_data = json_get(it, "data");
+
+ if (event_type == NULL || event_data == NULL)
continue;
- }
- // remove received messages from map
- for (std::map<std::string, bool>::iterator it = proto->facy.messages_ignore.begin(); it != proto->facy.messages_ignore.end(); ++it) {
- if (it->second)
- proto->facy.messages_ignore.erase(it);
+ std::string t = json_as_string(event_type);
+ if (t == "visibility_update") {
+ // change of chat status
+ JSONNODE *visibility = json_get(event_data, "visibility");
+
+ bool isVisible = (visibility != NULL) && json_as_bool(visibility);
+ proto->Log(" Requested chat switch to %s", isVisible ? "Online" : "Offline");
+ proto->SetStatus(isVisible ? ID_STATUS_ONLINE : ID_STATUS_INVISIBLE);
+ }
}
+ else
+ continue;
}
- catch (Reader::ParseException& e)
- {
- proto->Log("!!!!! Caught json::ParseException: %s", e.what());
- proto->Log(" Line/offset: %d/%d", e.m_locTokenBegin.m_nLine + 1, e.m_locTokenBegin.m_nLineOffset + 1);
- }
- catch (const Exception& e)
- {
- proto->Log ("!!!!! Caught json::Exception: %s", e.what());
+
+ // remove received messages from map
+ for (std::map<std::string, bool>::iterator it = proto->facy.messages_ignore.begin(); it != proto->facy.messages_ignore.end(); ++it) {
+ if (it->second)
+ proto->facy.messages_ignore.erase(it);
}
return EXIT_SUCCESS;
|