/* * Copyright 2010, Dario Casalinuovo. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Partially based on the msntest program inclused in libmsn. * */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "MSN.h" #include "MSNContainer.h" const char* kProtocolSignature = "msn"; const char* kProtocolName = "MSN Protocol"; const uint32 kAvatarCheckMessage = 'AVMs'; struct pollfd* kPollSockets = NULL; struct Ssl { bool isSSL; bool isConnected; SSL *ssl; SSL_CTX *ctx; } *kSocketsSsl = NULL; int kSocketsCount = 0; int kSocketsAvailable = 0; class AvatarLooper : public BLooper { public: AvatarLooper(MSNP* owner) : fOwner(owner) {}; virtual ~AvatarLooper() {}; virtual void MessageReceived(BMessage* message) { switch (message->what) { case kAvatarCheckMessage: { printf("msg\n"); fOwner->AvatarQueueCheck(); break; } default: BLooper::MessageReceived(message); } } private: MSNP* fOwner; }; int32 StartPollThread(void* punt) { MSNP* mainClass = (MSNP*) punt; MSN::NotificationServerConnection* mainConnection = mainClass->GetConnection(); mainConnection->connect("messenger.hotmail.com", 1863); while (1) { fflush(stdout); if (kPollSockets == NULL) continue; poll(kPollSockets, kSocketsCount, 3); for (int i = 0; i < kSocketsCount; i++) { if (kPollSockets[i].fd == -1) { continue; } if (kPollSockets[i].revents & POLLHUP) { kPollSockets[i].revents = 0; continue; } if (kPollSockets[i].revents & (POLLIN | POLLOUT | POLLPRI)) { MSN::Connection *c; c = mainConnection->connectionWithSocket((void*)kPollSockets[i].fd); if (c != NULL) { // TODO make the ssl code more styled and less bugged if (kSocketsSsl[i].isSSL && !kSocketsSsl[i].isConnected) { BIO *bio_socket_new; SSL_METHOD *meth=NULL; meth=const_cast(SSLv23_client_method()); SSL_library_init(); kSocketsSsl[i].ctx = SSL_CTX_new(meth); kSocketsSsl[i].ssl = SSL_new(kSocketsSsl[i].ctx); bio_socket_new = BIO_new_socket(kPollSockets[i].fd, BIO_CLOSE); if (!kSocketsSsl[i].ssl) break; BIO_set_nbio(bio_socket_new, 0); SSL_set_bio(kSocketsSsl[i].ssl, bio_socket_new, bio_socket_new); SSL_set_mode(kSocketsSsl[i].ssl, SSL_MODE_AUTO_RETRY); // TODO - fix-me - not async and buggy // and handle errors /*int ret =*/ SSL_connect(kSocketsSsl[i].ssl); kSocketsSsl[i].isConnected = true; } if (c->isConnected() == false) c->socketConnectionCompleted(); if (kPollSockets[i].revents & POLLIN) { if (kSocketsSsl[i].isSSL && kSocketsSsl[i].isConnected) { if (SSL_want_read(kSocketsSsl[i].ssl)) { kPollSockets[i].revents = 0; continue; } } c->dataArrivedOnSocket(); } if (kPollSockets[i].revents & POLLOUT) { c->socketIsWritable(); } } } if (kPollSockets[i].revents & (POLLERR | POLLNVAL)) { MSN::Connection *c; c = mainConnection->connectionWithSocket((void*)kPollSockets[i].fd); if (c != NULL) { delete c; } kPollSockets[i].fd = -1; kPollSockets[i].revents = 0; continue; } } if (kPollSockets[0].revents & POLLIN) { kPollSockets[0].revents = 0; } } return 0; } /* MSNP Class implementing libmsn callbacks and the Caya internal protocol */ MSNP::MSNP() : fUsername(""), fServer("messenger.hotmail.com"), fPassword(""), fMainConnection(NULL), fSettings(false), fCachePath(""), fRunnerTime(40000000) { AvatarLooper* fAvatarLooper = new AvatarLooper(this); BMessenger* mess = new BMessenger(NULL, fAvatarLooper); if (!mess->IsValid()) { printf("Avatar BMessenger error\n"); } fAvatarLooper->Run(); fAvatarRunner = new BMessageRunner(*mess, new BMessage(kAvatarCheckMessage), fRunnerTime); if (fAvatarRunner->InitCheck() != B_OK) { printf("Avatar MessageRunner error %s\n", strerror(fAvatarRunner->InitCheck())); } } MSNP::~MSNP() { Shutdown(); } status_t MSNP::Init(CayaProtocolMessengerInterface* msgr) { fServerMsgr = msgr; fLogged = false; fClientID = 0; fClientID += MSN::MSNC7; fClientID += MSN::MSNC6; fClientID += MSN::MSNC5; fClientID += MSN::MSNC4; fClientID += MSN::MSNC3; fClientID += MSN::MSNC2; fClientID += MSN::MSNC1; fClientID += MSN::SupportWinks; fClientID += MSN::VoiceClips; fClientID += MSN::InkGifSupport; fClientID += MSN::SIPInvitations; fClientID += MSN::SupportMultiPacketMessaging; fID = 963396; BPath path; status_t ret = find_directory(B_USER_CONFIG_DIRECTORY, &path); if (ret != B_OK) return ret; BDirectory cacheDir = BDirectory(path.Path()); path.Append("settings/Caya/Cache/msn/"); cacheDir.CreateDirectory(path.Path(), NULL); fCachePath = path; return B_OK; } status_t MSNP::Shutdown() { // LogOut(); delete fAvatarRunner; delete fAvatarLooper; return B_OK; } CayaProtocolMessengerInterface* MSNP::MessengerInterface() const { return fServerMsgr; } MSN::NotificationServerConnection* MSNP::GetConnection() const { return fMainConnection; } status_t MSNP::Process(BMessage* msg) { // printf("Process()\n"); // msg->PrintToStream(); switch (msg->what) { case IM_MESSAGE: { int32 im_what = 0; msg->FindInt32("im_what", &im_what); switch (im_what) { case IM_SET_OWN_NICKNAME: { BString nick; if (msg->FindString("nick", &nick) == B_OK) { if (fLogged) { fMainConnection->setFriendlyName(nick.String(), true); fNickname = nick.String(); } else { fNickname = nick.String(); } } break; } case IM_SET_OWN_STATUS: { int32 status = msg->FindInt32("status"); BString status_msg(""); msg->FindString("message", &status_msg); switch (status) { case CAYA_ONLINE: if (fLogged) { fMainConnection->setState(MSN::STATUS_AVAILABLE, fClientID); } else if (fSettings) { if (fMainConnection != NULL) break; if (fUsername == "") Error("Empty Username!", NULL); if (fPassword == "") Error("Empty Password!",NULL); //Progress("MSN Protocol: Login", "MSNP: Connecting...", 0.0f); MSN::Passport username; try { username = MSN::Passport(fUsername.c_str()); } catch (MSN::InvalidPassport & e) { Error("MSN Protocol: Invalid Passport!", "Error!"); return B_ERROR; } MSN::Callbacks* cb = dynamic_cast (this); fMainConnection = new MSN::NotificationServerConnection(username, fPassword.String(), *cb); resume_thread(fPollThread); } else { Error("MSN Protocol: Settings Error", NULL); } break; case CAYA_AWAY: if (fLogged) fMainConnection->setState(MSN::STATUS_AWAY, fClientID); break; case CAYA_CUSTOM_STATUS: break; case CAYA_DO_NOT_DISTURB: if (fLogged) fMainConnection->setState(MSN::STATUS_IDLE, fClientID); break; case CAYA_OFFLINE: if (fLogged) { fMainConnection->disconnect(); delete fMainConnection; fMainConnection = NULL; int end = fBuddyList.CountItems(); for (int x=0; x != end; x++) { MSN::Buddy contact = fBuddyList.ItemAt(x); if (contact.lists & MSN::LST_AL ) { BMessage msg(IM_MESSAGE); msg.AddInt32("im_what", IM_STATUS_SET); msg.AddString("protocol", kProtocolSignature); msg.AddString("id", contact.userName.c_str()); msg.AddInt32("status", CAYA_OFFLINE); fServerMsgr->SendMessage(&msg); } } fLogged = false; fSettings = true; suspend_thread(fPollThread); } else { delete fMainConnection; fMainConnection = NULL; suspend_thread(fPollThread); } break; } break; } case IM_SEND_MESSAGE: { const char* buddy = msg->FindString("id"); const char* sms = msg->FindString("body"); int x, y; bool nouveau = true; int count = 0; count = fSwitchboardList.CountItems(); if (count != 0) { for (x=0; x < count; x++) { if (fSwitchboardList.ItemAt(x)->first == buddy) { if (fSwitchboardList.ItemAt(x)->second->isConnected()) { nouveau = false; y = x; } else { delete fSwitchboardList.ItemAt(x)->second; fSwitchboardList.RemoveItemAt(x); } break; } } } if (nouveau) { MSNContainer* container = new MSNContainer(string(sms), string(buddy)); fMainConnection->requestSwitchboardConnection(container); } else { MSN::SwitchboardServerConnection* conn = fSwitchboardList.ItemAt(y)->second; if (conn != NULL && conn->isConnected()) { conn->sendTypingNotification(); conn->sendMessage(string(sms)); } BMessage msg(IM_MESSAGE); msg.AddInt32("im_what", IM_MESSAGE_SENT); msg.AddString("protocol", kProtocolSignature); msg.AddString("id", buddy); msg.AddString("body", sms); fServerMsgr->SendMessage(&msg); } break; } case IM_REGISTER_CONTACTS: { break; } case IM_UNREGISTER_CONTACTS: { break; } case IM_USER_STARTED_TYPING: { const char* id = msg->FindString("id"); int x; int count = 0; count = fSwitchboardList.CountItems(); if (count != 0) { for (x=0; x < count; x++) { if (fSwitchboardList.ItemAt(x)->first == id) { if (fSwitchboardList.ItemAt(x)->second != NULL) fSwitchboardList.ItemAt(x)->second->sendTypingNotification(); break; } } } break; } case IM_USER_STOPPED_TYPING: { break; } case IM_GET_CONTACT_INFO: break; default: // We don't handle this im_what code //LOG(kProtocolName, liDebug, "Got unhandled message: %ld", im_what); //msg->PrintToStream(); return B_ERROR; } break; } default: // We don't handle this what code return B_ERROR; } return B_OK; } const char* MSNP::Signature() const { return kProtocolSignature; } const char* MSNP::FriendlySignature() const { return kProtocolName; } status_t MSNP::UpdateSettings(BMessage* msg) { printf("updatesettings\n"); const char* usernm = NULL; const char* password = NULL; msg->FindString("username", &usernm); msg->FindString("password", &password); if ((usernm == NULL) || (password == NULL)) { Error("Error: Username or Password Empty",NULL); return B_ERROR; } fUsername = usernm; fPassword.SetTo(password); fSettings = true; fPollThread = spawn_thread(StartPollThread, "MSNP-PollThread", B_NORMAL_PRIORITY, this); return B_OK; } uint32 MSNP::GetEncoding() { return 0xffff; } // other stuff void MSNP::Error(const char* message, const char* who) { BMessage msg(IM_ERROR); msg.AddString("protocol", kProtocolSignature); if (who) msg.AddString("id", who); msg.AddString("error", message); _SendMessage(&msg); } void MSNP::_NotifyProgress(const char* title, const char* message, float progress) { BMessage msg(IM_MESSAGE); msg.AddInt32("im_what", IM_PROGRESS); msg.AddString("title", title); msg.AddString("message", message); msg.AddFloat("progress", progress); _SendMessage(&msg); } void MSNP::_Notify(notification_type type, const char* title, const char* message) { BMessage msg(IM_MESSAGE); msg.AddInt32("im_what", IM_NOTIFICATION); msg.AddInt32("type", (int32)type); msg.AddString("title", title); msg.AddString("message", message); _SendMessage(&msg); } void MSNP::_SendMessage(BMessage* msg) { // Skip invalid messages if (!msg) return; msg->AddString("protocol", kProtocolSignature); fServerMsgr->SendMessage(msg); } uint32 MSNP::Version() const { return CAYA_VERSION_1_PRE_ALPHA_1; } void MSNP::SendContactInfo(MSN::Buddy buddy) { int32 what = IM_CONTACT_INFO; BMessage msg(IM_MESSAGE); msg.AddInt32("im_what", what); msg.AddString("protocol", kProtocolSignature); msg.AddString("id", buddy.userName.c_str()); msg.AddString("name", buddy.friendlyName.c_str()); msg.AddString("email", buddy.userName.c_str()); // Send contact information fServerMsgr->SendMessage(&msg); } void MSNP::MessageFromBuddy(const char* mess, const char* id) { BMessage msg(IM_MESSAGE); msg.AddInt32("im_what", IM_MESSAGE_RECEIVED); msg.AddString("protocol", kProtocolSignature); msg.AddString("id", id); msg.AddString("body", mess); fServerMsgr->SendMessage(&msg); } void MSNP::RequestBuddyIcon(string msnobject, MSN::Passport buddy) { MSNContainer* container = new MSNContainer(buddy); container->SetObject(msnobject); fMainConnection->requestSwitchboardConnection(container); } void MSNP::RequestBuddyIcon(MSN::SwitchboardServerConnection* conn, string msnobject, const char* buddy) { fID = fID+1; BString path = GetFilename(msnobject).Path(); if (path == "") { conn->disconnect(); return; } conn->requestDisplayPicture(fID, path.String(), msnobject); } void MSNP::SendBuddyIcon(string filename, string passport) { entry_ref ref; if (get_ref_for_path(filename.c_str(), &ref) != B_OK) return; BMessage msg(IM_MESSAGE); msg.AddInt32("im_what", IM_AVATAR_SET); msg.AddString("id", passport.c_str()); msg.AddRef("ref", &ref); fServerMsgr->SendMessage(&msg); } bool MSNP::CheckAvatar(string msnobject, string passport) { BPath filepath = GetFilename(msnobject); BEntry entry = BEntry(filepath.Path(), true); if (entry.Exists()) { if (passport != "" && filepath != "") SendBuddyIcon(filepath.Path(), passport); return true; } return false; } void MSNP::AvatarQueueCheck() { if (fAvatarQueue.CountItems() > 0) { pair* item = fAvatarQueue.ItemAt(0); fAvatarQueue.RemoveItemAt(0); printf("avatar check %s\n", item->first.c_str()); RequestBuddyIcon(item->second, item->first); fAvatarDone.AddItem(item); } else { fAvatarRunner->SetCount(0); } } string MSNP::GetObject(string passport) { for (uint32 i = 0; i < fAvatarQueue.CountItems(); i++) { if (fAvatarQueue.ItemAt(i)->first == passport) return fAvatarQueue.ItemAt(i)->second; } for (uint32 i = 0; i < fAvatarDone.CountItems(); i++) { if (fAvatarDone.ItemAt(i)->first == passport) return fAvatarDone.ItemAt(i)->second; } return ""; } BPath MSNP::GetFilename(string msnobject) { BString str = FindSHA1D(msnobject); if (str.Length() < 25) return ""; BPath path = fCachePath; path.Append(str); return path; } BString MSNP::FindSHA1D(string msnobject) { BString str = BString(msnobject.c_str()); BString ret; int32 index = str.FindFirst("SHA1D="); index += 7; str.CopyInto(ret, index, (int32) 27); ret.RemoveAll("/"); return ret.String(); } /********************/ /* libmsn callbacks */ /********************/ void MSNP::registerSocket(void *s, int reading, int writing, bool isSSL) { // printf("MSNP::registerSocket %d %d %d\n", reading, writing, isSSL); int x = 0; if (kSocketsCount == kSocketsAvailable) { printf("allocating memory\n"); kPollSockets = (struct pollfd*) realloc(kPollSockets, (kSocketsAvailable + 10) * sizeof(struct pollfd)); if (kPollSockets == NULL) { Error("Memory Error!!\n", NULL); return; } kSocketsSsl = (struct Ssl*) realloc(kSocketsSsl, (kSocketsAvailable + 10) * sizeof(struct Ssl)); if (kSocketsSsl == NULL) { Error("Memory Error!!\n", NULL); return; } kSocketsAvailable += 10; for (x=kSocketsCount; x < kSocketsAvailable; x++) { kPollSockets[x].fd = -1; kPollSockets[x].events = 0; kPollSockets[x].revents = 0; kSocketsSsl[x].isSSL = false; kSocketsSsl[x].isConnected = false; kSocketsSsl[x].ctx = NULL; kSocketsSsl[x].ssl = NULL; } x=kSocketsCount; kPollSockets[x].fd = getSocketFileDescriptor(s); kPollSockets[x].revents = 0; kPollSockets[x].events = 0; if (reading) kPollSockets[x].events |= POLLIN; if (writing) kPollSockets[x].events |= POLLOUT; if (isSSL) kSocketsSsl[x].isSSL = true; kSocketsCount++; return; } if (kPollSockets != NULL) { for (x = 0; x < kSocketsCount+kSocketsAvailable; x++) { if (getSocketFileDescriptor(s) == kPollSockets[x].fd || kPollSockets[x].fd == -1) { if(kPollSockets[x].fd == -1) kSocketsCount++; kPollSockets[x].fd = getSocketFileDescriptor(s); kPollSockets[x].events = 0; if (reading) kPollSockets[x].events |= POLLIN; if (writing) kPollSockets[x].events |= POLLOUT; if (isSSL) kSocketsSsl[x].isSSL = true; return; } } } } int MSNP::getSocketFileDescriptor (void *sock) { long a = (long)sock; return (int)a; } void MSNP::closeSocket(void *s) { // printf("MSNP::closeSocket\n"); int x; int i; for (x = 0; x < kSocketsCount; x++) { if (getSocketFileDescriptor(s) == kPollSockets[x].fd) { close(getSocketFileDescriptor(s)); if (kSocketsSsl[x].isSSL) { if (kSocketsSsl[x].ssl) { SSL_set_shutdown(kSocketsSsl[x].ssl, SSL_SENT_SHUTDOWN|SSL_RECEIVED_SHUTDOWN); SSL_free(kSocketsSsl[x].ssl); if (kSocketsSsl[x].ctx) SSL_CTX_free(kSocketsSsl[x].ctx); } } for (i = x; i < kSocketsCount; i++) { kPollSockets[i] = kPollSockets[i+1]; kSocketsSsl[i] = kSocketsSsl[i+1]; } i = kSocketsCount; kPollSockets[i].fd = -1; kPollSockets[i].revents = 0; kPollSockets[i].events = 0; kSocketsSsl[i].isConnected = false; kSocketsSsl[i].isSSL = false; kSocketsSsl[i].ctx = NULL; kSocketsSsl[i].ssl = NULL; } } kSocketsCount--; } void MSNP::unregisterSocket(void *s) { // printf("MSNP::unregisterSocket"); for (int x = 0; x < kSocketsCount; x++) { if (kPollSockets[x].fd == getSocketFileDescriptor(s)) kPollSockets[x].events = 0; } } void MSNP::gotFriendlyName(MSN::NotificationServerConnection * conn, std::string friendlyname) { BMessage msg(IM_MESSAGE); msg.AddInt32("im_what", IM_OWN_CONTACT_INFO); msg.AddString("protocol", kProtocolSignature); msg.AddString("id", fUsername.c_str()); msg.AddString("name", friendlyname.c_str()); fServerMsgr->SendMessage(&msg); } void MSNP::gotBuddyListInfo(MSN::NotificationServerConnection* conn, MSN::ListSyncInfo* info) { std::map::iterator i = info->contactList.begin(); std::map allContacts; //Progress("MSN Protocol Login", "MSN Protocol: Logged in!", 0.90); for (; i != info->contactList.end(); i++) { MSN::Buddy* contact = (*i).second; if (contact->lists & MSN::LST_AB ) { allContacts[contact->userName.c_str()]=0; allContacts[contact->userName.c_str()] |= MSN::LST_AB; } if (contact->lists & MSN::LST_AL) { allContacts[contact->userName.c_str()] |= MSN::LST_AL; //printf("-AL %s \n", contact.userName.c_str()); fBuddyList.AddItem(*contact); } if (contact->lists & MSN::LST_BL) { allContacts[contact->userName.c_str()] |= MSN::LST_BL; } if (contact->lists & MSN::LST_RL) { //printf("-RL %s \n", contact.userName.c_str()); } if (contact->lists & MSN::LST_PL) { //printf("-PL %s \n", contact.userName.c_str()); } if (contact->lists & MSN::LST_AL) { allContacts[contact->userName.c_str()] |= MSN::LST_AL; //printf("-AL %s \n", contact.userName.c_str()); fBuddyList.AddItem(*contact); } } conn->completeConnection(allContacts,info); } void MSNP::gotLatestListSerial(MSN::NotificationServerConnection * conn, std::string lastChange) { } void MSNP::gotGTC(MSN::NotificationServerConnection * conn, char c) { } void MSNP::gotOIMDeleteConfirmation(MSN::NotificationServerConnection * conn, bool success, std::string id) { } void MSNP::gotOIMSendConfirmation(MSN::NotificationServerConnection * conn, bool success, int id) { } void MSNP::gotOIM(MSN::NotificationServerConnection * conn, bool success, std::string id, std::string message) { } void MSNP::gotOIMList(MSN::NotificationServerConnection * conn, std::vector OIMs) { } void MSNP::connectionReady(MSN::Connection * conn) { fLogged = true; BMessage msg(IM_MESSAGE); msg.AddInt32("im_what", IM_OWN_STATUS_SET); msg.AddString("protocol", kProtocolSignature); msg.AddInt32("status", CAYA_ONLINE); fServerMsgr->SendMessage(&msg); BMessage serverBased(IM_MESSAGE); serverBased.AddInt32("im_what", IM_CONTACT_LIST); serverBased.AddString("protocol", kProtocolSignature); int end = fBuddyList.CountItems(); int x; for (x=0; x != end; x++) { MSN::Buddy contact = fBuddyList.ItemAt(x); if (contact.lists & MSN::LST_AL) { serverBased.AddString("id", contact.userName.c_str()); } } fServerMsgr->SendMessage(&serverBased); for (x=0; x != end; x++) { MSN::Buddy contact = fBuddyList.ItemAt(x); if (contact.lists & MSN::LST_AL) { SendContactInfo(contact); } } BString content(fUsername.c_str()); content << " has logged in!"; _Notify(B_INFORMATION_NOTIFICATION, "Connected", content.String()); fMainConnection->setState(MSN::STATUS_AVAILABLE, fClientID); } void MSNP::gotBLP(MSN::NotificationServerConnection * conn, char c) { } void MSNP::addedListEntry(MSN::NotificationServerConnection * conn, MSN::ContactList list, MSN::Passport username, std::string friendlyname) { } void MSNP::removedListEntry(MSN::NotificationServerConnection * conn, MSN::ContactList list, MSN::Passport username) { } void MSNP::addedGroup(MSN::NotificationServerConnection * conn, bool added, std::string groupName, std::string groupID) { } void MSNP::removedGroup(MSN::NotificationServerConnection * conn, bool removed, std::string groupID) { } void MSNP::renamedGroup(MSN::NotificationServerConnection * conn, bool renamed, std::string newGroupName, std::string groupID) { } void MSNP::showError(MSN::Connection * conn, std::string msg) { printf("MSNP::showError: %s", msg.c_str()); } void MSNP::buddyChangedStatus(MSN::NotificationServerConnection* conn, MSN::Passport buddy, std::string friendlyname, MSN::BuddyStatus status, unsigned int clientID, std::string msnobject) { printf("chngstat\n"); BMessage msg(IM_MESSAGE); msg.AddInt32("im_what", IM_STATUS_SET); msg.AddString("protocol", kProtocolSignature); msg.AddString("id", buddy.c_str()); switch(status) { case MSN::STATUS_AVAILABLE : msg.AddInt32("status", CAYA_ONLINE); break; case MSN::STATUS_AWAY : msg.AddInt32("status", CAYA_AWAY); break; case MSN::STATUS_IDLE : msg.AddInt32("status", CAYA_AWAY); break; case MSN::STATUS_BUSY : msg.AddInt32("status", CAYA_DO_NOT_DISTURB); break; case MSN::STATUS_BERIGHTBACK : msg.AddInt32("status", CAYA_AWAY); break; case MSN::STATUS_ONTHEPHONE : msg.AddInt32("status", CAYA_DO_NOT_DISTURB); break; case MSN::STATUS_OUTTOLUNCH : msg.AddInt32("status", CAYA_AWAY); break; default : msg.AddInt32("status", CAYA_OFFLINE); break; } fServerMsgr->SendMessage(&msg); // updating the user informations BMessage mess(IM_MESSAGE); mess.AddInt32("im_what", IM_CONTACT_INFO); //mess.AddString("protocol", kProtocolSignature); msg.AddString("id", buddy.c_str()); msg.AddString("name", friendlyname.c_str()); fServerMsgr->SendMessage(&msg); if(!CheckAvatar(msnobject, buddy)) { for (uint32 i = 0; i < fAvatarQueue.CountItems(); i++) { if (fAvatarQueue.ItemAt(i)->first == buddy) { delete fAvatarQueue.ItemAt(i); fAvatarQueue.RemoveItemAt(i); } } for (uint32 i = 0; i < fAvatarDone.CountItems(); i++) { if (fAvatarDone.ItemAt(i)->first == buddy) delete fAvatarDone.ItemAt(i); fAvatarDone.RemoveItemAt(i); } fAvatarQueue.AddItem(new pair(buddy, msnobject)); bigtime_t time; int32 count; fAvatarRunner->GetInfo(&time, &count); if (count == 0) fAvatarRunner->SetCount(-1); } else { for (uint32 i = 0; i < fAvatarDone.CountItems(); i++) { if (fAvatarDone.ItemAt(i)->first == buddy) fAvatarDone.ItemAt(i)->second = msnobject; return; } fAvatarDone.AddItem(new pair(buddy, msnobject)); } } void MSNP::buddyOffline(MSN::NotificationServerConnection* conn, MSN::Passport buddy) { if(conn->switchboardWithOnlyUser(buddy) != NULL) { delete conn->switchboardWithOnlyUser(buddy); } BMessage msg(IM_MESSAGE); msg.AddInt32("im_what", IM_STATUS_SET); msg.AddString("protocol", kProtocolSignature); msg.AddString("id", buddy.c_str()); msg.AddInt32("status", CAYA_OFFLINE); fServerMsgr->SendMessage(&msg); } void MSNP::gotSwitchboard(MSN::SwitchboardServerConnection* conn, const void* tag) { if (!tag) return; MSNContainer* cont = (MSNContainer*) tag; if (cont->IsMessage()) { fSwitchboardList.AddItem( new pair(cont->Buddy(), conn)); } conn->inviteUser(cont->Buddy()); } void MSNP::buddyJoinedConversation(MSN::SwitchboardServerConnection* conn, MSN::Passport username, std::string friendlyname, int is_initial) { if (!conn->auth.tag) return; MSNContainer* cont = (MSNContainer*) (conn->auth.tag); if (cont->IsMessage()) { conn->sendTypingNotification(); /*int trid = */conn->sendMessage(cont->Message()); } if (cont->HasObject() && !cont->IsMessage()) { if (!CheckAvatar(cont->Object(), cont->Buddy().c_str())) RequestBuddyIcon(conn, cont->Object(), cont->Buddy().c_str()); } delete cont; conn->auth.tag = NULL; } void MSNP::buddyLeftConversation(MSN::SwitchboardServerConnection* conn, MSN::Passport username) { //printf("MSNP::buddyLeftConversation\n"); } void MSNP::gotInstantMessage(MSN::SwitchboardServerConnection* conn, MSN::Passport username, std::string friendlyname, MSN::Message* msg) { MessageFromBuddy(msg->getBody().c_str(), username.c_str()); } void MSNP::gotEmoticonNotification(MSN::SwitchboardServerConnection* conn, MSN::Passport username, std::string alias, std::string msnobject) { //printf("MSNP::gotEmoticonNotification\n"); } void MSNP::failedSendingMessage(MSN::Connection* conn) { //TODO implement it } void MSNP::buddyTyping(MSN::SwitchboardServerConnection* conn, MSN::Passport username, std::string friendlyname) { BMessage msg(IM_MESSAGE); msg.AddInt32("im_what", IM_CONTACT_STARTED_TYPING); msg.AddString("protocol", kProtocolSignature); msg.AddString("id", username.c_str()); fServerMsgr->SendMessage(&msg); } void MSNP::gotNudge(MSN::SwitchboardServerConnection* conn, MSN::Passport username) { MessageFromBuddy("** Nudge!!!", username.c_str()); } void MSNP::gotVoiceClipNotification(MSN::SwitchboardServerConnection* conn, MSN::Passport username, std::string msnobject) { MessageFromBuddy("** Sent you a Voice Clip, but Caya cannot yet display it", username.c_str()); } void MSNP::gotWinkNotification(MSN::SwitchboardServerConnection * conn, MSN::Passport username, std::string msnobject) { MessageFromBuddy("** Sent you a Wink, but Caya cannot yet display it", username.c_str()); } void MSNP::gotInk(MSN::SwitchboardServerConnection * conn, MSN::Passport username, std::string image) { MessageFromBuddy("** Sent you an Ink draw, but Caya cannot yet display it", username.c_str()); } void MSNP::gotContactDisplayPicture(MSN::SwitchboardServerConnection* conn, MSN::Passport passport, std::string filename ) { //printf("MSNP::gotContactDisplayPicture %s\n", filename.c_str()); SendBuddyIcon(filename, passport); conn->disconnect(); } void MSNP::gotActionMessage(MSN::SwitchboardServerConnection * conn, MSN::Passport username, std::string message) { //printf("MSNP::gotActionMessage\n"); } void MSNP::gotInitialEmailNotification(MSN::NotificationServerConnection * conn, int msgs_inbox, int unread_inbox, int msgs_folders, int unread_folders) { } void MSNP::gotNewEmailNotification(MSN::NotificationServerConnection * conn, std::string from, std::string subject) { } void MSNP::fileTransferInviteResponse(MSN::SwitchboardServerConnection * conn, unsigned int sessionID, bool response) { } void MSNP::fileTransferProgress(MSN::SwitchboardServerConnection * conn, unsigned int sessionID, unsigned long long transferred, unsigned long long total) { } void MSNP::fileTransferFailed(MSN::SwitchboardServerConnection * conn, unsigned int sessionID, MSN::fileTransferError error) { //printf("file transfer failed\n"); } void MSNP::fileTransferSucceeded(MSN::SwitchboardServerConnection * conn, unsigned int sessionID) { } void MSNP::gotNewConnection(MSN::Connection* conn) { // this is at least what the method should do. if (dynamic_cast(conn)) dynamic_cast(conn)->synchronizeContactList(); // we call synchronizeContactList and the callback GotBuddyListInfo is called // from libmsn if all goes well } void MSNP::buddyChangedPersonalInfo(MSN::NotificationServerConnection* conn, MSN::Passport fromPassport, MSN::personalInfo pInfo) { int32 what = IM_CONTACT_INFO; BMessage msg(IM_MESSAGE); msg.AddInt32("im_what", what); msg.AddString("id", fromPassport.c_str()); msg.AddString("protocol", kProtocolSignature); msg.AddString("message", pInfo.PSM.c_str()); fServerMsgr->SendMessage(&msg); } void MSNP::closingConnection(MSN::Connection* conn) { // TODO there should be a class that provide those // strings, also in prevision of the localization support if (conn->sock == fMainConnection->sock) { BString content(fUsername.c_str()); content << " has logged out!"; _Notify(B_INFORMATION_NOTIFICATION, "Disconnected", content.String()); } printf ("MSNP::closingConnection : connection with socket %d\n", (int)conn->sock); int x; int count = 0; count = fSwitchboardList.CountItems(); // TODO use libmsn methods to retrieve the switchboard if (count != 0) { for (x = 0; x < count; x++) { if (fSwitchboardList.ItemAt(x)->second->sock == conn->sock) { fSwitchboardList.RemoveItemAt(x); break; } } } } void MSNP::changedStatus(MSN::NotificationServerConnection* conn, MSN::BuddyStatus state) { MSN::personalInfo pInfo; // pInfo.PSM="From Caya at Haiku OS - www.haiku-os.org"; conn->setPersonalStatus(pInfo); } void * MSNP::connectToServer(std::string hostname, int port, bool *connected, bool isSSL) { // printf("MSNP::connectToServer\n"); struct sockaddr_in sa; struct hostent *hp; int s; if ((hp = gethostbyname(hostname.c_str())) == NULL) { errno = ECONNREFUSED; return (void*)-1; } memset(&sa,0,sizeof(sa)); memcpy((char *)&sa.sin_addr,hp->h_addr,hp->h_length); /* set address */ sa.sin_family = (uint8_t)hp->h_addrtype; sa.sin_port = htons((u_short)port); if ((s = socket(hp->h_addrtype,SOCK_STREAM,0)) < 0) /* get socket */ return (void*)-1; int oldfdArgs = fcntl(s, F_GETFL, 0); fcntl(s, F_SETFL, oldfdArgs | O_NONBLOCK); if (connect(s,(struct sockaddr *)&sa,sizeof sa) < 0) { if (errno != EINPROGRESS) { close(s); return (void*)-1; } *connected = false; } else { *connected = true; } return (void*)s; } int MSNP::listenOnPort(int port) { // printf("MSNP::listenOnPort\n"); int s; struct sockaddr_in addr; if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) { return -1; } memset(&addr, 0, sizeof(addr)); addr.sin_family = AF_INET; addr.sin_port = htons((uint16)port); if (bind(s, (sockaddr *)(&addr), sizeof(addr)) < 0 || listen(s, 1) < 0) { close(s); return -1; } return s; } std::string MSNP::getOurIP(void) { struct hostent* hn; char buf2[1024]; gethostname(buf2, 1024); hn = gethostbyname(buf2); return inet_ntoa( *((struct in_addr*)hn->h_addr)); } void MSNP::log(int i, const char *s) { printf("MSNP::log %s\n", s); } std::string MSNP::getSecureHTTPProxy() { return ""; } void MSNP::gotMessageSentACK(MSN::SwitchboardServerConnection * conn, int trID) { } void MSNP::askFileTransfer(MSN::SwitchboardServerConnection * conn, MSN::fileTransferInvite ft) { //printf("file transfer\n"); } void MSNP::addedContactToGroup(MSN::NotificationServerConnection * conn, bool added, std::string groupId, std::string contactId) { } void MSNP::removedContactFromGroup(MSN::NotificationServerConnection * conn, bool removed, std::string groupId, std::string contactId) { } void MSNP::addedContactToAddressBook(MSN::NotificationServerConnection * conn, bool added, std::string passport, std::string displayName, std::string guid) { } void MSNP::removedContactFromAddressBook(MSN::NotificationServerConnection * conn, bool removed, std::string contactId, std::string passport) { } void MSNP::enabledContactOnAddressBook(MSN::NotificationServerConnection * conn, bool enabled, std::string contactId, std::string passport) { } void MSNP::disabledContactOnAddressBook(MSN::NotificationServerConnection * conn, bool disabled, std::string contactId) { } size_t MSNP::getDataFromSocket (void* sock, char* data, size_t size) { // printf("MSNP::getDataFromSocket\n"); int idx=0; bool ssl_done = false; int newAmountRead = 0; for (int i = 0; i < kSocketsCount; i++) { if (kPollSockets[i].fd == getSocketFileDescriptor(sock)) { idx = i; break; } } if (!kSocketsSsl[idx].isSSL) { int newWritten = ::recv(getSocketFileDescriptor(sock), data, size, 0); if (errno == EAGAIN) return -1; return newWritten; } if (!kSocketsSsl[idx].isConnected) return 0; while (!ssl_done) { if (!kSocketsSsl[idx].ssl) break; newAmountRead = SSL_read(kSocketsSsl[idx].ssl, data, size); switch(SSL_get_error(kSocketsSsl[idx].ssl, newAmountRead)) { case SSL_ERROR_NONE: return newAmountRead; case SSL_ERROR_ZERO_RETURN: return 0; case SSL_ERROR_WANT_READ: case SSL_ERROR_WANT_WRITE: ssl_done=false; break; case SSL_ERROR_SSL: return 0; break; case SSL_ERROR_SYSCALL: return 0; break; default: return newAmountRead; } } return 0; } size_t MSNP::writeDataToSocket (void* sock, char* data, size_t size) { // printf("MSNP::writeDataToSocket\n"); size_t written = 0; int idx; for (int i = 0; i < kSocketsCount; i++) { if (kPollSockets[i].fd == getSocketFileDescriptor(sock)) { idx = i; break; } } while (written < size) { int newWritten; if (kSocketsSsl[idx].isSSL) { if (!kSocketsSsl[idx].isConnected) return 0; newWritten = SSL_write(kSocketsSsl[idx].ssl, data, (int) (size - written)); int error = SSL_get_error(kSocketsSsl[idx].ssl,newWritten); switch (error) { case SSL_ERROR_NONE: written += newWritten; data+=newWritten; break; case SSL_ERROR_WANT_WRITE: case SSL_ERROR_WANT_READ: continue; case SSL_ERROR_ZERO_RETURN: break; case SSL_ERROR_SYSCALL: default: break; } } else { newWritten = ::send(getSocketFileDescriptor(sock), data, (int)(size - written), 0); if (newWritten <= 0) { if (errno == EAGAIN) { continue; } else { break; } } written += newWritten; data+=newWritten; } } if (written != size) { showError(NULL, "Error on socket"); unregisterSocket(sock); closeSocket(sock); return written; } return written; } void MSNP::gotVoiceClipFile(MSN::SwitchboardServerConnection* conn, unsigned int sessionID, std::string file) { } void MSNP::gotEmoticonFile(MSN::SwitchboardServerConnection* conn, unsigned int sessionID, std::string alias, std::string file) { } void MSNP::gotWinkFile(MSN::SwitchboardServerConnection* conn, unsigned int sessionID, std::string file) { } void MSNP::gotInboxUrl(MSN::NotificationServerConnection* conn, MSN::hotmailInfo info) { }