12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054 |
- /*
- * Copyright 2010, Pier Luigi Fiorini. All rights reserved.
- * Copyright 2021, Jaidyn Levesque. All rights reserved.
- * Distributed under the terms of the GPL v2 License.
- *
- * Authors:
- * Pier Luigi Fiorini, pierluigi.fiorini@gmail.com
- * Jaidyn Levesque, jadedctrl@teknik.io
- */
- #include <iostream>
- #include <Catalog.h>
- #include <Directory.h>
- #include <Entry.h>
- #include <File.h>
- #include <FindDirectory.h>
- #include <List.h>
- #include <StringList.h>
- #include <libsupport/SHA1.h>
- #include <ChatProtocolMessages.h>
- #include <Flags.h>
- #include <Role.h>
- #include <gloox/chatstatefilter.h>
- #include <gloox/messageeventfilter.h>
- #include <gloox/mucroom.h>
- #include "JabberHandler.h"
- #undef B_TRANSLATION_CONTEXT
- #define B_TRANSLATION_CONTEXT "JabberHandler"
- static status_t
- connect_thread(void* data)
- {
- JabberHandler* handler = (JabberHandler*)data;
- if (!handler)
- return B_BAD_VALUE;
- gloox::Client* client = handler->Client();
- if (!client)
- return B_BAD_VALUE;
- gloox::ConnectionError e;
- while ((e = client->recv(10000000)) == gloox::ConnNoError);
- if (e != gloox::ConnUserDisconnected)
- handler->HandleConnectionError(e);
- return B_OK;
- }
- JabberHandler::JabberHandler()
- :
- fClient(NULL),
- fVCardManager(NULL),
- fSession(NULL),
- fLastOwnVCard(0)
- {
- fAvatars = new BList();
- }
- JabberHandler::~JabberHandler()
- {
- Shutdown();
- BString* item = NULL;
- for (int32 i = 0; (item = (BString*)fAvatars->ItemAt(i)); i++)
- delete item;
- delete fAvatars;
- }
- status_t
- JabberHandler::Init(ChatProtocolMessengerInterface* messenger)
- {
- fServerMessenger = messenger;
- return B_OK;
- }
- status_t
- JabberHandler::Process(BMessage* msg)
- {
- if (msg->what != IM_MESSAGE)
- return B_ERROR;
- int32 im_what = 0;
- msg->FindInt32("im_what", &im_what);
- switch (im_what) {
- case IM_SET_OWN_STATUS:
- {
- int32 status = msg->FindInt32("status");
- BString status_msg = msg->FindString("message");
- switch (status) {
- case STATUS_ONLINE:
- // Log in if we still need to
- resume_thread(fRecvThread);
- break;
- case STATUS_OFFLINE:
- kill_thread(fRecvThread);
- break;
- default:
- break;
- }
- break;
- }
- case IM_SET_OWN_NICKNAME:
- {
- const char* nick = msg->FindString("user_name");
- if (nick != NULL)
- for (int i = 0; i < fRooms.CountItems(); i++)
- fRooms.ValueAt(i)->setNick(nick);
- break;
- }
- case IM_SEND_MESSAGE:
- {
- const char* id = msg->FindString("chat_id");
- const char* subject = msg->FindString("subject");
- const char* body = msg->FindString("body");
- gloox::MUCRoom* room = fRooms.ValueFor(id);
- if (!id || !body)
- return B_ERROR;
- // Send JabberHandler message
- gloox::Message jm(gloox::Message::Chat, gloox::JID(id),
- body, (subject ? subject : gloox::EmptyString));
- if (room != NULL) {
- room->send(body);
- break;
- }
- else
- fClient->send(jm);
- // If non-MUC, tell Caya we actually sent the message
- // (An MUC should echo the message back to us later, see
- // handleMUCMessage)
- _MessageSent(id, subject, body);
- break;
- }
- case IM_CREATE_CHAT:
- {
- const char* user_id = msg->FindString("user_id");
- // TODO: Contact validation, make sure permssion is granted
- if (!user_id)
- return B_ERROR;
- _EnsureUserChat(user_id);
- _ChatCreatedMsg(user_id);
- break;
- }
- case IM_CREATE_ROOM:
- {
- BString chat_id;
- if (msg->FindString("chat_id", &chat_id) != B_OK)
- break;
- _JoinRoom(chat_id);
- break;
- }
- case IM_JOIN_ROOM:
- {
- BString chat_id;
- if (msg->FindString("chat_id", &chat_id) == B_OK)
- _JoinRoom(chat_id.String());
- break;
- }
- case IM_LEAVE_ROOM:
- {
- BString chat_id = msg->FindString("chat_id");
- gloox::MUCRoom* room = fRooms.ValueFor(chat_id);
- // MUCs are special, one-on-ones we can just drop
- if (room != NULL)
- room->leave();
- // We've gotta let Caya know!
- BMessage left(IM_MESSAGE);
- left.AddInt32("im_what", IM_ROOM_LEFT);
- left.AddString("chat_id", chat_id);
- _SendMessage(&left);
- break;
- }
- case IM_ROOM_INVITE_ACCEPT:
- {
- BString chat_id;
- if (msg->FindString("chat_id", &chat_id) != B_OK)
- break;
- BStringList splitAtPassword;
- chat_id.Split("#", false, splitAtPassword);
- chat_id = splitAtPassword.StringAt(0);
- _JoinRoom(chat_id.String());
- break;
- }
- case IM_ROOM_SEND_INVITE:
- {
- BString chat_id = msg->FindString("chat_id");
- gloox::MUCRoom* room = fRooms.ValueFor(chat_id);
- BString user_id;
- if (room == NULL || msg->FindString("user_id", &user_id) != B_OK)
- break;
- room->invite(gloox::JID(user_id.String()), "");
- break;
- }
- case IM_GET_ROOM_PARTICIPANTS:
- {
- BString chat_id = msg->FindString("chat_id");
- gloox::MUCRoom* room = fRooms.ValueFor(chat_id);
- if (room != NULL)
- room->getRoomItems();
- else if (fUserChats.HasString(chat_id) == true) {
- BMessage users(IM_MESSAGE);
- users.AddInt32("im_what", IM_ROOM_PARTICIPANTS);
- users.AddString("user_id", chat_id);
- }
- break;
- }
- case IM_GET_ROOM_METADATA:
- {
- BString chat_id = msg->FindString("chat_id");
- gloox::MUCRoom* room = fRooms.ValueFor(chat_id);
- if (room != NULL)
- room->getRoomInfo();
- if (fUserChats.HasString(chat_id) == true)
- {
- BMessage metadata(IM_MESSAGE);
- metadata.AddInt32("im_what", IM_ROOM_METADATA);
- metadata.AddString("chat_id", chat_id);
- metadata.AddInt32("room_default_flags", 0 | ROOM_LOG_LOCALLY
- | ROOM_POPULATE_LOGS | ROOM_NOTIFY_DM);
- metadata.AddInt32("room_disallowed_flags", 0 | ROOM_AUTOJOIN
- | ROOM_AUTOCREATE);
- _SendMessage(&metadata);
- }
- break;
- }
- case IM_SET_ROOM_SUBJECT:
- {
- BString chat_id = msg->FindString("chat_id");
- gloox::MUCRoom* room = fRooms.ValueFor(chat_id);
- if (room != NULL)
- room->setSubject(msg->GetString("subject", ""));
- break;
- }
- case IM_GET_EXTENDED_CONTACT_INFO:
- {
- BString user_id;
- if (msg->FindString("user_id", &user_id) == B_OK)
- fVCardManager->fetchVCard(gloox::JID(user_id.String()), this);
- break;
- }
- case IM_ROSTER_ADD_CONTACT:
- {
- BString user_name = msg->FindString("user_name");
- BString user_id;
- if (msg->FindString("user_id", &user_id) != B_OK)
- break;
- fClient->rosterManager()->add(gloox::JID(user_id.String()),
- user_name.String(), gloox::StringList());
- fClient->rosterManager()->subscribe(gloox::JID(user_id.String()),
- user_name.String());
- fClient->rosterManager()->synchronize();
- break;
- }
- case IM_ROSTER_REMOVE_CONTACT:
- {
- BString user_id;
- if (msg->FindString("user_id", &user_id) != B_OK)
- break;
- fClient->rosterManager()->remove(gloox::JID(user_id.String()));
- fClient->rosterManager()->unsubscribe(gloox::JID(user_id.String()));
- fClient->rosterManager()->synchronize();
- BMessage rm(IM_MESSAGE);
- rm.AddInt32("im_what", IM_ROSTER_CONTACT_REMOVED);
- rm.AddString("user_id", user_id);
- _SendMessage(&rm);
- break;
- }
- case IM_ROSTER_EDIT_CONTACT:
- {
- BString user_id;
- BString user_name = msg->FindString("user_name");
- if (msg->FindString("user_id", &user_id) != B_OK)
- break;
- gloox::JID jid(user_id.String());
- gloox::RosterItem* item =
- fClient->rosterManager()->getRosterItem(jid);
- if (item != NULL && user_name.IsEmpty() == false) {
- item->setName(user_name.String());
- fClient->rosterManager()->synchronize();
- }
- break;
- }
- case IM_ROOM_KICK_PARTICIPANT:
- case IM_ROOM_BAN_PARTICIPANT:
- case IM_ROOM_UNBAN_PARTICIPANT:
- case IM_ROOM_MUTE_PARTICIPANT:
- case IM_ROOM_UNMUTE_PARTICIPANT:
- _MUCModeration(msg);
- break;
- default:
- return B_ERROR;
- }
- return B_OK;
- }
- status_t
- JabberHandler::Shutdown()
- {
- if (fVCardManager)
- fVCardManager->cancelVCardOperations(this);
- if (fClient)
- fClient->disposeMessageSession(fSession);
- kill_thread(fRecvThread);
- return B_OK;
- }
- void
- JabberHandler::SetAddOnPath(BPath path)
- {
- fPath = path;
- }
- BPath
- JabberHandler::AddOnPath()
- {
- return fPath;
- }
- void
- JabberHandler::SetName(const char* name)
- {
- fName = name;
- }
- const char*
- JabberHandler::GetName()
- {
- return fName.String();
- }
- BObjectList<BMessage>
- JabberHandler::Commands()
- {
- return BObjectList<BMessage>();
- }
- BObjectList<BMessage>
- JabberHandler::ChatPopUpItems()
- {
- return BObjectList<BMessage>();
- }
- BObjectList<BMessage>
- JabberHandler::UserPopUpItems()
- {
- return BObjectList<BMessage>();
- }
- BObjectList<BMessage>
- JabberHandler::MenuBarItems()
- {
- return BObjectList<BMessage>();
- }
- status_t
- JabberHandler::UpdateSettings(BMessage* msg)
- {
- const char* username = msg->FindString("username");
- const char* password = msg->FindString("password");
- const char* server = msg->FindString("server");
- const char* resource = msg->FindString("resource");
- // Sanity check
- if (!username || !password || !resource)
- return B_ERROR;
- // Store settings
- fUsername = username;
- fNick = username;
- fPassword = password;
- fServer = server;
- fResource = resource;
- fPort = 5222;
- // Give the add-on a change to override settings
- OverrideSettings();
- // Compose JID
- BString jid = ComposeJID();
- fJid.setJID(jid.String());
- // Register our client
- fClient = new OurClient(fJid, fPassword.String());
- fClient->setServer(fServer.String());
- if (fPort > 0)
- fClient->setPort(fPort);
- fClient->registerConnectionListener(this);
- fClient->registerMessageSessionHandler(this);
- fClient->registerMUCInvitationHandler(new InviteHandler(fClient, this));
- fClient->rosterManager()->registerRosterListener(this);
- fClient->disco()->setVersion("Chat-O-Matic", VERSION);
- fClient->disco()->setIdentity("client", "chat-o-matic");
- fClient->logInstance().registerLogHandler(gloox::LogLevelDebug,
- gloox::LogAreaAll, this);
- // Register vCard manager
- fVCardManager = new gloox::VCardManager(fClient);
- // Connect to the server
- fClient->connect(false);
- // Read data from another thread
- fRecvThread = spawn_thread(connect_thread, "connect_thread",
- B_NORMAL_PRIORITY, (void*)this);
- if (fRecvThread < B_OK)
- return B_ERROR;
- return B_OK;
- }
- uint32
- JabberHandler::GetEncoding()
- {
- return 0xffff;
- }
- ChatProtocolMessengerInterface*
- JabberHandler::MessengerInterface() const
- {
- return fServerMessenger;
- }
- gloox::Client*
- JabberHandler::Client() const
- {
- return fClient;
- }
- void
- JabberHandler::HandleConnectionError(gloox::ConnectionError& e)
- {
- #undef B_TRANSLATION_CONTEXT
- #define B_TRANSLATION_CONTEXT "JabberHandler ― Connection errors"
- // Handle error
- BMessage errMsg(IM_ERROR);
- switch (e) {
- case gloox::ConnStreamError:
- {
- #undef B_TRANSLATION_CONTEXT
- #define B_TRANSLATION_CONTEXT "JabberHandler ― Connection stream errors"
- gloox::StreamError streamError = fClient->streamError();
- errMsg.AddString("error", B_TRANSLATE("Bad or malformed XML stream."));
- switch (streamError) {
- case gloox::StreamErrorBadFormat:
- errMsg.AddString("detail", B_TRANSLATE("The entity has "
- "sent XML that cannot be processed"));
- break;
- case gloox::StreamErrorBadNamespacePrefix:
- errMsg.AddString("detail", B_TRANSLATE("The entity has "
- "sent a namespace prefix which is not supported, "
- "or has sent no namespace prefix on an element "
- "that requires such prefix."));
- break;
- case gloox::StreamErrorConflict:
- errMsg.AddString("detail", B_TRANSLATE("The server is "
- "closing the active stream for this entity "
- "because a new stream has been initiated that "
- "conflicts with the existing stream."));
- break;
- case gloox::StreamErrorConnectionTimeout:
- errMsg.AddString("detail", B_TRANSLATE("The entity has "
- "not generated any traffic over the stream for "
- "some period of time."));
- break;
- case gloox::StreamErrorHostGone:
- errMsg.AddString("detail", B_TRANSLATE("The host initially "
- "used corresponds to a hostname that is no longer "
- "hosted by the server."));
- break;
- case gloox::StreamErrorHostUnknown:
- errMsg.AddString("detail", B_TRANSLATE("The host initially "
- "used does not correspond to a hostname that is "
- "hosted by the server."));
- break;
- case gloox::StreamErrorImproperAddressing:
- errMsg.AddString("detail", B_TRANSLATE("A stanza sent "
- "between two servers lacks a 'to' or 'from' "
- "attribute (or the attribute has no value."));
- break;
- case gloox::StreamErrorInternalServerError:
- errMsg.AddString("detail", B_TRANSLATE("The server has "
- "experienced a misconfiguration or an "
- "otherwise-undefined internal error that prevents "
- "it from servicing the stream."));
- break;
- case gloox::StreamErrorInvalidFrom:
- errMsg.AddString("detail", B_TRANSLATE("The JID or "
- "hostname provided in a 'from' address does not "
- "match an authorized JID or validated domain "
- "negotiation between servers via SASL or dialback, "
- "or between a client and a server via "
- "authentication and resource binding."));
- break;
- case gloox::StreamErrorInvalidId:
- errMsg.AddString("detail", B_TRANSLATE("The stream ID or "
- "dialback ID is invalid or does not match and ID "
- "previously provdided."));
- break;
- case gloox::StreamErrorInvalidNamespace:
- errMsg.AddString("detail", B_TRANSLATE("The streams "
- "namespace name is something other than "
- "\"http://etherx.jabber.org/streams\" or the "
- "dialback namespace name is something other than "
- "\"jabber:server:dialback\"."));
- break;
- case gloox::StreamErrorInvalidXml:
- errMsg.AddString("detail", B_TRANSLATE("The entity has "
- "sent invalid XML over the stream to a server that "
- "performs validation."));
- break;
- case gloox::StreamErrorNotAuthorized:
- errMsg.AddString("detail", B_TRANSLATE("The entity has "
- "attempted to send data before the stream has been "
- "authenticated, or otherwise is not authorized to "
- "perform an action related to stream negotiation; "
- "the receiving entity must not process the "
- "offending stanza before sending the stream "
- "error."));
- break;
- case gloox::StreamErrorPolicyViolation:
- errMsg.AddString("detail", B_TRANSLATE("The entity has "
- "violated some local service policy; the server "
- "may choose to specify the policy in the <text/> "
- "element or an application-specific condition "
- "element."));
- break;
- case gloox::StreamErrorRemoteConnectionFailed:
- errMsg.AddString("detail", B_TRANSLATE("The server is "
- "unable to properly connect to a remote entity "
- "that is required for authentication."));
- break;
- case gloox::StreamErrorResourceConstraint:
- errMsg.AddString("detail", B_TRANSLATE("The server lacks "
- "the system resources necessary to service the "
- "stream."));
- break;
- case gloox::StreamErrorRestrictedXml:
- errMsg.AddString("detail", B_TRANSLATE("The entity has "
- "attempted to send restricted XML features such as "
- "a comment, processing instruction, DTD, entity "
- "reference or unescaped character."));
- break;
- case gloox::StreamErrorSeeOtherHost:
- errMsg.AddString("detail", B_TRANSLATE("The server will "
- "not provide service to the initiating entity but "
- "is redirecting traffic to another host; the "
- "server should specify the alternate hostname or "
- "IP address (which MUST be a valid domain "
- "identifier) as the XML characted data of the "
- "<see-other-host/> element."));
- break;
- case gloox::StreamErrorSystemShutdown:
- errMsg.AddString("detail", B_TRANSLATE("The server is "
- "being shut down and all active streams are being "
- "closed."));
- break;
- case gloox::StreamErrorUndefinedCondition:
- errMsg.AddString("detail", B_TRANSLATE("The error "
- "condition is not one of those defined by the "
- "other condition in this list; this error "
- "condition should be used only in conjunction with "
- "an application-specific condition."));
- break;
- case gloox::StreamErrorUnsupportedEncoding:
- errMsg.AddString("detail", B_TRANSLATE("The initiating "
- "entity has encoded the stream in an encoding "
- "that is not supported by the server."));
- break;
- case gloox::StreamErrorUnsupportedStanzaType:
- errMsg.AddString("detail", B_TRANSLATE("The initiating "
- "entity has sent a first-level child of the stream "
- "that is not supported by the server."));
- break;
- case gloox::StreamErrorUnsupportedVersion:
- errMsg.AddString("detail", B_TRANSLATE("The value of the "
- "'version' attribute provided by the initiating "
- "entity in the stream header specifies a version "
- "of XMPP that is not supported by the server; the "
- "server may specify the version(s) it supports in "
- "the <text/> element."));
- break;
- case gloox::StreamErrorXmlNotWellFormed:
- errMsg.AddString("detail", B_TRANSLATE("The initiating "
- "entity has sent XML that is not well-formed as "
- "defined by XML."));
- break;
- default:
- break;
- }
- break;
- }
- case gloox::ConnStreamVersionError:
- errMsg.AddString("detail", B_TRANSLATE("The incoming stream's "
- "version is not supported."));
- break;
- case gloox::ConnStreamClosed:
- errMsg.AddString("detail", B_TRANSLATE("The stream has been closed "
- "by the server."));
- break;
- case gloox::ConnProxyAuthRequired:
- errMsg.AddString("detail", B_TRANSLATE("The HTTP/SOCKS5 proxy "
- "requires authentication."));
- break;
- case gloox::ConnProxyAuthFailed:
- errMsg.AddString("detail", B_TRANSLATE("HTTP/SOCKS5 proxy "
- "authentication failed."));
- break;
- case gloox::ConnProxyNoSupportedAuth:
- errMsg.AddString("detail", B_TRANSLATE("The HTTP/SOCKS5 proxy "
- "requires an unsupported authentication mechanism."));
- break;
- case gloox::ConnIoError:
- errMsg.AddString("detail", B_TRANSLATE("Input/output error."));
- break;
- case gloox::ConnParseError:
- errMsg.AddString("detail", B_TRANSLATE("A XML parse error "
- "occurred."));
- break;
- case gloox::ConnConnectionRefused:
- errMsg.AddString("detail", B_TRANSLATE("The connection was refused "
- "by the server on the socket level."));
- break;
- case gloox::ConnDnsError:
- errMsg.AddString("detail", B_TRANSLATE("Server's hostname "
- "resolution failed."));
- break;
- case gloox::ConnOutOfMemory:
- errMsg.AddString("detail", B_TRANSLATE("Out of memory."));
- break;
- case gloox::ConnTlsFailed:
- errMsg.AddString("detail", B_TRANSLATE("The server's certificate "
- "could not be verified or the TLS handshake did not "
- "complete successfully."));
- break;
- case gloox::ConnTlsNotAvailable:
- errMsg.AddString("detail", B_TRANSLATE("The server didn't offer "
- "TLS while it was set to be required, or TLS was not "
- "compiled in."));
- break;
- case gloox::ConnCompressionFailed:
- errMsg.AddString("detail", B_TRANSLATE("Negotiating or "
- "initializing compression failed."));
- break;
- case gloox::ConnAuthenticationFailed:
- {
- #undef B_TRANSLATION_CONTEXT
- #define B_TRANSLATION_CONTEXT "JabberHandler ― Connection authentication errors"
- gloox::AuthenticationError authError = fClient->authError();
- errMsg.AddString("error", B_TRANSLATE("Authentication failed. "
- "Username or password wrong or account does not "
- "exist."));
- switch (authError) {
- case gloox::SaslAborted:
- errMsg.AddString("detail", B_TRANSLATE("The receiving "
- "entity acknowledges an <abort/> element sent by "
- "initiating entity; sent in reply to the <abort/> "
- "element."));
- break;
- case gloox::SaslIncorrectEncoding:
- errMsg.AddString("detail", B_TRANSLATE("The data provided "
- "by the initiating entity could not be processed "
- "because the base64 encoding is incorrect."));
- break;
- case gloox::SaslInvalidAuthzid:
- errMsg.AddString("detail", B_TRANSLATE("The authid "
- "provided by the initiating entity is invalid, "
- "either because it is incorrectly formatted or "
- "because the initiating entity does not have "
- "permissions to authorize that ID; sent in reply "
- "to a <response/> element or an <auth/> element "
- "with initial response data."));
- break;
- case gloox::SaslInvalidMechanism:
- errMsg.AddString("detail", B_TRANSLATE("The initiating "
- "element did not provide a mechanism or requested "
- "a mechanism that is not supported by the "
- "receiving entity; sent in reply to an <auth/> "
- "element."));
- break;
- case gloox::SaslMalformedRequest:
- errMsg.AddString("detail", B_TRANSLATE("The request is "
- "malformed (e.g., the <auth/> element includes an "
- "initial response but the mechanism does not "
- "allow that); sent in reply to an <abort/>, "
- "<auth/>, <challenge/>, or <response/> element."));
- break;
- case gloox::SaslMechanismTooWeak:
- errMsg.AddString("detail", B_TRANSLATE("The mechanism "
- "requested by the initiating entity is weaker "
- "than server policy permits for that initiating "
- "entity; sent in reply to a <response/> element or "
- "an <auth/> element with initial response data."));
- break;
- case gloox::SaslNotAuthorized:
- errMsg.AddString("detail", B_TRANSLATE("The authentication "
- "failed because the initiating entity did not "
- "provide valid credentials (this includes but is "
- "not limited to the case of an unknown username); "
- "sent in reply to a <response/> element or an "
- "<auth/> element with initial response data."));
- break;
- case gloox::SaslTemporaryAuthFailure:
- errMsg.AddString("detail", B_TRANSLATE("The authentication "
- "failed because of a temporary error condition "
- "within the receiving entity; sent in reply to an "
- "<auth/> element or <response/> element."));
- break;
- case gloox::NonSaslConflict:
- errMsg.AddString("detail", B_TRANSLATE("Resource conflict, "
- "see XEP-0078."));
- break;
- case gloox::NonSaslNotAcceptable:
- errMsg.AddString("detail", B_TRANSLATE("Required "
- "information not provided, see XEP-0078."));
- break;
- case gloox::NonSaslNotAuthorized:
- errMsg.AddString("detail", B_TRANSLATE("Incorrect "
- "credentials."));
- break;
- default:
- break;
- }
- break;
- }
- case gloox::ConnNotConnected: {
- BMessage disconnect(IM_MESSAGE);
- disconnect.AddInt32("im_what", IM_PROTOCOL_DISABLE);
- _SendMessage(&disconnect);
- break;
- }
- default:
- break;
- }
- _SendMessage(&errMsg);
- }
- void
- JabberHandler::HandleStanzaError(gloox::StanzaError error)
- {
- #undef B_TRANSLATION_CONTEXT
- #define B_TRANSLATION_CONTEXT "JabberHandler ― Stanza errors"
- BMessage errMsg(IM_ERROR);
- errMsg.AddString("error", B_TRANSLATE("Stanza-related error"));
- BString detail;
- switch (error)
- {
- case gloox::StanzaErrorBadRequest:
- detail = B_TRANSLATE("The sender has sent XML that is malformed or "
- "that cannot be processed.");
- break;
- case gloox::StanzaErrorConflict:
- detail = B_TRANSLATE("Access cannot be granted because an existing "
- "resource or session exists with the same name or address.");
- break;
- case gloox::StanzaErrorFeatureNotImplemented:
- detail = B_TRANSLATE("This feature hasn't been implemented by the "
- "recipient or by the server.");
- break;
- case gloox::StanzaErrorForbidden:
- detail = B_TRANSLATE("You don't have permssion to do this.");
- break;
- case gloox::StanzaErrorGone:
- detail = B_TRANSLATE("The recipient or server can no longer be "
- "contacted at this address. Try again later, or with a "
- "different address.");
- break;
- case gloox::StanzaErrorInternalServerError:
- detail = B_TRANSLATE("The server could not process the stanza "
- "because of a misconfiguration or an otherwise-undefined "
- "internal server error.");
- break;
- case gloox::StanzaErrorItemNotFound:
- detail = B_TRANSLATE("The addressed JID or item requested cannot "
- "be found.");
- break;
- case gloox::StanzaErrorJidMalformed:
- detail = B_TRANSLATE("An invalid XMPP address or identifier was "
- "given. If you can, please try a different one.");
- break;
- case gloox::StanzaErrorNotAcceptable:
- detail = B_TRANSLATE("The server or user refuses to accept this, "
- "because some criteria hasn't been met (e.g., a local policy "
- "regarding acceptable words in messages).");
- break;
- case gloox::StanzaErrorNotAllowed:
- detail = B_TRANSLATE("You aren't allowed to do this by the server "
- "or recepient.");
- break;
- case gloox::StanzaErrorNotAuthorized:
- detail = B_TRANSLATE("You need to be properily authenticated "
- "before doing this.");
- case gloox::StanzaErrorNotModified:
- detail = B_TRANSLATE("The item requested has not changed since it "
- "was last requested.");
- case gloox::StanzaErrorPaymentRequired:
- detail = B_TRANSLATE("The server refuses to offer service, because "
- "payment is required.");
- break;
- case gloox::StanzaErrorRecipientUnavailable:
- detail = B_TRANSLATE("The recipient is temporarily unavailable.");
- break;
- case gloox::StanzaErrorRedirect:
- detail = B_TRANSLATE("The recipient or server is redirecting "
- "requests for this information to another entity, usually "
- "temporarily.");
- break;
- case gloox::StanzaErrorRegistrationRequired:
- detail = B_TRANSLATE("You can't do this before registration! Be "
- "sure your finished registering for your account.");
- break;
- case gloox::StanzaErrorRemoteServerNotFound:
- detail = B_TRANSLATE("That user's server doesn't exist.");
- break;
- case gloox::StanzaErrorRemoteServerTimeout:
- detail = B_TRANSLATE("Connection to that user's server has timed "
- "out.");
- break;
- case gloox::StanzaErrorResourceConstraint:
- detail = B_TRANSLATE("The server or recipient are too busy right "
- "now; try again later.");
- break;
- case gloox::StanzaErrorServiceUnavailable:
- detail = B_TRANSLATE("The server or recipient don't provide this "
- "service.");
- break;
- case gloox::StanzaErrorSubscribtionRequired:
- detail = B_TRANSLATE("You can't access this unless you are "
- "subscribed.");
- break;
- }
- errMsg.AddString("detail", detail);
- _SendMessage(&errMsg);
- }
- void
- JabberHandler::_SendMessage(BMessage* msg)
- {
- // Skip invalid messages
- if (!msg)
- return;
- msg->AddString("protocol", Signature());
- fServerMessenger->SendMessage(msg);
- }
- void
- JabberHandler::_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
- JabberHandler::_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
- JabberHandler::_MessageSent(const char* id, const char* subject,
- const char* body)
- {
- BMessage msg(IM_MESSAGE);
- msg.AddInt32("im_what", IM_MESSAGE_SENT);
- msg.AddString("user_id", fJid.bare().c_str());
- msg.AddString("chat_id", id);
- msg.AddString("subject", subject);
- msg.AddString("body", body);
- _SendMessage(&msg);
- }
- void
- JabberHandler::_ChatCreatedMsg(const char* id)
- {
- BMessage msg(IM_MESSAGE);
- msg.AddInt32("im_what", IM_CHAT_CREATED);
- msg.AddString("chat_id", id);
- msg.AddString("user_id", id);
- _SendMessage(&msg);
- }
- void
- JabberHandler::_RoleChangedMsg(BString chat_id, BString user_id,
- gloox::MUCRoomRole role, gloox::MUCRoomAffiliation aff)
- {
- BMessage roleMsg(IM_MESSAGE);
- roleMsg.AddInt32("im_what", IM_ROOM_ROLECHANGED);
- roleMsg.AddString("user_id", user_id);
- roleMsg.AddString("chat_id", chat_id);
- roleMsg.AddString("role_title", _RoleTitle(role, aff));
- roleMsg.AddInt32("role_perms", _RolePerms(role, aff));
- roleMsg.AddInt32("role_priority", _RolePriority(role, aff));
- _SendMessage(&roleMsg);
- }
- void
- JabberHandler::_UserLeftMsg(BString chat_id, gloox::MUCRoomParticipant participant)
- {
- BString user_id;
- const char* nick = participant.nick->resource().c_str();
- bool isSelf = _MUCUserId(chat_id, nick, &user_id);
- if (user_id.IsEmpty() == true)
- return;
- int32 im_what = IM_ROOM_PARTICIPANT_LEFT;
- int flags = participant.flags;
- if (flags & gloox::UserBanned)
- im_what = IM_ROOM_PARTICIPANT_BANNED;
- else if (flags & gloox::UserKicked)
- im_what = IM_ROOM_PARTICIPANT_KICKED;
- BMessage leftMsg(IM_MESSAGE);
- leftMsg.AddInt32("im_what", im_what);
- leftMsg.AddString("chat_id", chat_id);
- leftMsg.AddString("user_id", user_id);
- leftMsg.AddString("user_name", nick);
- if (participant.reason.empty() == false)
- leftMsg.AddString("body", participant.reason.c_str());
- _SendMessage(&leftMsg);
- }
- void
- JabberHandler::_StatusSetMsg(const char* user_id, gloox::Presence::PresenceType type,
- const char* message, const char* resource)
- {
- BMessage msg(IM_MESSAGE);
- msg.AddInt32("im_what", IM_USER_STATUS_SET);
- msg.AddString("user_id", user_id);
- msg.AddInt32("status", _GlooxStatusToApp(type));
- if (BString(resource).IsEmpty() == false)
- msg.AddString("resource", resource);
- if (BString(message).IsEmpty() == false)
- msg.AddString("message", message);
- _SendMessage(&msg);
- }
- void
- JabberHandler::_EnsureUserChat(const char* chat_id)
- {
- if (fUserChats.HasString(BString(chat_id)) == false)
- fUserChats.Add(BString(chat_id));
- }
- status_t
- JabberHandler::_SetupAvatarCache()
- {
- if (fAvatarCachePath.InitCheck() == B_OK)
- return B_OK;
- BPath path;
- if (find_directory(B_SYSTEM_TEMP_DIRECTORY, &path) != B_OK)
- return B_ERROR;
- path.Append(GetName());
- if (create_directory(path.Path(), 0755) != B_OK)
- return B_ERROR;
- fCachePath = path;
- path.Append("avatar-cache");
- BFile file(path.Path(), B_READ_ONLY);
- fAvatarCache.Unflatten(&file);
- fAvatarCachePath = path;
- return B_OK;
- }
- status_t
- JabberHandler::_SaveAvatarCache()
- {
- if (fAvatarCachePath.InitCheck() != B_OK)
- return B_ERROR;
- BFile file(fAvatarCachePath.Path(), B_CREATE_FILE | B_WRITE_ONLY | B_ERASE_FILE);
- return fAvatarCache.Flatten(&file);
- }
- void
- JabberHandler::_CacheAvatar(const char* id, const char* binimage, size_t length)
- {
- if (!id || !binimage || length <= 0)
- return;
- // Calculate avatar hash
- CSHA1 s1;
- char hash[256];
- s1.Reset();
- s1.Update((uchar*)binimage, length);
- s1.Final();
- s1.ReportHash(hash, CSHA1::REPORT_HEX);
- BString sha1;
- sha1.SetTo(hash, 256);
- BString oldSha1;
- if (fAvatarCache.FindString(id, &oldSha1) != B_OK || oldSha1 == "" || sha1 != oldSha1) {
- // Replace old hash and save cache
- fAvatarCache.RemoveName(id);
- fAvatarCache.AddString(id, sha1);
- _SaveAvatarCache();
- if (oldSha1 != "") {
- BPath path(fCachePath);
- path.Append(oldSha1);
- // Remove old image file
- BEntry entry(path.Path());
- entry.Remove();
- // Remove old hash from the list
- BString* item = NULL;
- for (int32 i = 0; (item = (BString*)fAvatars->ItemAt(i)); i++) {
- if (item->Compare(oldSha1) == 0) {
- fAvatars->RemoveItem(item);
- break;
- }
- }
- }
- }
- // Determine file path
- BPath path(fCachePath);
- path.Append(sha1);
- BEntry entry(path.Path());
- if (!entry.Exists()) {
- // Save to file
- BFile file(path.Path(), B_CREATE_FILE | B_WRITE_ONLY | B_ERASE_FILE);
- file.Write(binimage, length);
- }
- // Do we need to notify the app?
- bool found = false;
- BString* item = NULL;
- for (int32 i = 0; (item = (BString*)fAvatars->ItemAt(i)); i++) {
- if (item->Compare(sha1) == 0) {
- found = true;
- break;
- }
- }
- if (!found) {
- // Add new hash to the list if needed
- fAvatars->AddItem(new BString(sha1));
- // Notify Caya that the avatar has changed
- _AvatarChanged(id, path.Path());
- }
- }
- void
- JabberHandler::_AvatarChanged(const char* id, const char* filename)
- {
- entry_ref ref;
- if (get_ref_for_path(filename, &ref) != B_OK)
- return;
- BMessage msg(IM_MESSAGE);
- if (fJid.bare() == id)
- msg.AddInt32("im_what", IM_OWN_AVATAR_SET);
- else {
- msg.AddInt32("im_what", IM_USER_AVATAR_SET);
- msg.AddString("user_id", id);
- }
- msg.AddRef("ref", &ref);
- _SendMessage(&msg);
- }
- UserStatus
- JabberHandler::_GlooxStatusToApp(gloox::Presence::PresenceType type)
- {
- switch (type) {
- case gloox::Presence::Available:
- case gloox::Presence::Chat:
- return STATUS_ONLINE;
- case gloox::Presence::Away:
- return STATUS_AWAY;
- case gloox::Presence::XA:
- return STATUS_CUSTOM_STATUS;
- case gloox::Presence::DND:
- return STATUS_DO_NOT_DISTURB;
- case gloox::Presence::Unavailable:
- return STATUS_OFFLINE;
- default:
- break;
- }
- return STATUS_OFFLINE;
- }
- BString
- JabberHandler::_MUCChatId(gloox::MUCRoom* room)
- {
- BString chat_id(room->name().c_str());
- chat_id << "@" << room->service().c_str();
- BStringList parts;
- chat_id.Split("/", false, parts);
- return parts.StringAt(0);
- }
- bool
- JabberHandler::_MUCUserId(BString chat_id, const char* nick, BString* id)
- {
- BString chat(chat_id);
- chat << "/" << nick;
- // If sent from own user, use normal ID
- if (nick == fNick) {
- *id = fJid.bare().c_str();
- return true;
- }
- *id = chat;
- return false;
- }
- void
- JabberHandler::_JoinRoom(const char* chat_id)
- {
- BString join_id(chat_id);
- join_id << "/" << fNick;
- gloox::MUCRoom* room = fRooms.ValueFor(chat_id);
- if (room == NULL)
- room = new gloox::MUCRoom(fClient, gloox::JID(join_id.String()), this, this);
- room->join();
- fRooms.AddItem(BString(chat_id), room);
- }
- void
- JabberHandler::_MUCModeration(BMessage* msg)
- {
- BString chat_id = msg->FindString("chat_id");
- BString user_id;
- BString body = msg->FindString("body");
- gloox::MUCRoom* room = fRooms.ValueFor(chat_id);
- if (room == NULL || msg->FindString("user_id", &user_id) != B_OK)
- return;
- std::string nick = gloox::JID(user_id.String()).resource();
- switch (msg->FindInt32("im_what"))
- {
- case IM_ROOM_KICK_PARTICIPANT:
- room->kick(nick, body.String());
- break;
- case IM_ROOM_BAN_PARTICIPANT:
- room->ban(nick, body.String());
- break;
- case IM_ROOM_MUTE_PARTICIPANT:
- room->revokeVoice(nick, body.String());
- break;
- case IM_ROOM_UNMUTE_PARTICIPANT:
- room->grantVoice(nick, body.String());
- break;
- }
- }
- const char*
- JabberHandler::_RoleTitle(gloox::MUCRoomRole role, gloox::MUCRoomAffiliation aff)
- {
- #undef B_TRANSLATION_CONTEXT
- #define B_TRANSLATION_CONTEXT "JabberHandler ― User roles"
- switch (role)
- {
- case gloox::RoleVisitor:
- return B_TRANSLATE("Visitor");
- case gloox::RoleParticipant:
- return B_TRANSLATE("Member");
- case gloox::RoleModerator:
- if (aff == gloox::AffiliationOwner)
- return B_TRANSLATE("Owner");
- return B_TRANSLATE("Moderator");
- }
- return B_TRANSLATE("Invalid");
- }
- int32
- JabberHandler::_RolePerms(gloox::MUCRoomRole role, gloox::MUCRoomAffiliation aff)
- {
- switch (role)
- {
- case gloox::RoleVisitor:
- return 0 | PERM_READ | PERM_NICK;
- case gloox::RoleParticipant:
- return 0 | PERM_READ | PERM_WRITE | PERM_ROOM_SUBJECT;
- case gloox::RoleModerator: {
- int32 perm = 0 | PERM_READ | PERM_WRITE | PERM_ROOM_SUBJECT
- | PERM_KICK | PERM_MUTE;
- if (aff == gloox::AffiliationOwner)
- perm = perm | PERM_ROLECHANGE | PERM_BAN;
- return perm;
- }
- }
- return 0;
- }
- int32
- JabberHandler::_RolePriority(gloox::MUCRoomRole role, gloox::MUCRoomAffiliation aff)
- {
- switch (role)
- {
- case gloox::RoleParticipant:
- return 1;
- case gloox::RoleModerator:
- if (aff == gloox::AffiliationOwner)
- return 3;
- return 2;
- }
- return 0;
- }
- BMessage
- JabberHandler::_SettingsTemplate(const char* username, bool serverOption)
- {
- #undef B_TRANSLATION_CONTEXT
- #define B_TRANSLATION_CONTEXT "JabberHandler ― Settings template"
- BMessage stemplate('IMst');
- BMessage usernameText;
- usernameText.AddString("name", "username");
- usernameText.AddString("description", username);
- usernameText.AddString("error", B_TRANSLATE("You can't log into an account "
- "without a username.\nPlease fill in your username for the given "
- "server."));
- usernameText.AddInt32("type", 'CSTR');
- stemplate.AddMessage("setting", &usernameText);
- BMessage passwordText;
- passwordText.AddString("name", "password");
- passwordText.AddString("description", B_TRANSLATE("Password:"));
- passwordText.AddString("error", B_TRANSLATE("You can't log into an account "
- "without a password.\nPlease fill in your password for the given "
- "account."));
- passwordText.AddInt32("type", 'CSTR');
- passwordText.AddBool("is_secret", true);
- stemplate.AddMessage("setting", &passwordText);
- BMessage serverText;
- serverText.AddString("name", "server");
- serverText.AddString("description", B_TRANSLATE("Server:"));
- serverText.AddString("error", B_TRANSLATE("You can't add an account "
- "without a server.\nPlease add a valid XMPP server."));
- serverText.AddInt32("type", 'CSTR');
- if (serverOption == true)
- stemplate.AddMessage("setting", &serverText);
- BMessage resourceText;
- resourceText.AddString("name", "resource");
- resourceText.AddString("description", B_TRANSLATE("Resource:"));
- resourceText.AddInt32("type", 'CSTR');
- resourceText.AddString("default", "Chat-O-Matic");
- resourceText.AddString("error", B_TRANSLATE("You can't add an account "
- "without a resource.\nDon't worry― it can be whatever string you "
- "want."));
- stemplate.AddMessage("setting", &resourceText);
- return stemplate;
- }
- BMessage
- JabberHandler::_RoomTemplate()
- {
- #undef B_TRANSLATION_CONTEXT
- #define B_TRANSLATION_CONTEXT "JabberHandler ― Room template"
- BMessage stemplate('IMst');
- BMessage roomIdentifier;
- roomIdentifier.AddString("name", "chat_id");
- roomIdentifier.AddString("description", B_TRANSLATE("Room ID:"));
- roomIdentifier.AddString("error", B_TRANSLATE("You can't have a room "
- "without a JID!\nUse the \"name@server\" format."));
- roomIdentifier.AddInt32("type", 'CSTR');
- stemplate.AddMessage("setting", &roomIdentifier);
- return stemplate;
- }
- BMessage
- JabberHandler::_RosterTemplate()
- {
- #undef B_TRANSLATION_CONTEXT
- #define B_TRANSLATION_CONTEXT "JabberHandler ― Roster template"
- BMessage stemplate('IMst');
- BMessage user_id;
- user_id.AddString("name", "user_id");
- user_id.AddString("description", B_TRANSLATE("User ID:"));
- user_id.AddString("error", B_TRANSLATE("You can't befriend an IDless "
- "miscreant!\nPlease use the \"name@server\" format."));
- user_id.AddInt32("type", 'CSTR');
- stemplate.AddMessage("setting", &user_id);
- BMessage user_name;
- user_name.AddString("name", "user_name");
- user_name.AddString("description", B_TRANSLATE("Nickname:"));
- user_name.AddInt32("type", 'CSTR');
- stemplate.AddMessage("setting", &user_name);
- return stemplate;
- }
- /***********************************************************************
- * gloox callbacks
- **********************************************************************/
- void
- JabberHandler::onConnect()
- {
- // We are online
- BMessage msg(IM_MESSAGE);
- msg.AddInt32("im_what", IM_OWN_STATUS_SET);
- msg.AddInt32("status", STATUS_ONLINE);
- _SendMessage(&msg);
- fVCardManager->fetchVCard(fJid, this);
- }
- void
- JabberHandler::onDisconnect(gloox::ConnectionError e)
- {
- // We are offline
- BMessage msg(IM_MESSAGE);
- msg.AddInt32("im_what", IM_OWN_STATUS_SET);
- msg.AddInt32("status", STATUS_OFFLINE);
- _SendMessage(&msg);
- if (e == gloox::ConnNoError) {
- // Notify our offline status
- BString content(fUsername);
- content << " has logged out!";
- _Notify(B_INFORMATION_NOTIFICATION, "Disconnected",
- content.String());
- return;
- }
- // Handle error
- HandleConnectionError(e);
- }
- bool
- JabberHandler::onTLSConnect(const gloox::CertInfo& info)
- {
- return true;
- }
- void
- JabberHandler::onResourceBindError(const gloox::Error* error)
- {
- }
- void
- JabberHandler::handleRoster(const gloox::Roster& roster)
- {
- std::list<BMessage> msgs;
- BMessage contactListMsg(IM_MESSAGE);
- contactListMsg.AddInt32("im_what", IM_ROSTER);
- gloox::Roster::const_iterator it = roster.begin();
- for (; it != roster.end(); ++it) {
- const char* jid = (*it).second->jidJID().full().c_str();
- const char* name = (*it).second->name().c_str();
- int32 subscription = (*it).second->subscription();
- // Add jid to the server based contact list message
- contactListMsg.AddString("user_id", jid);
- // Contact information message
- BMessage infoMsg(IM_MESSAGE);
- infoMsg.AddInt32("im_what", IM_CONTACT_INFO);
- infoMsg.AddString("user_id", jid);
- infoMsg.AddString("user_name", name);
- infoMsg.AddInt32("status", STATUS_OFFLINE);
- // Groups
- gloox::StringList g = (*it).second->groups();
- gloox::StringList::const_iterator it_g = g.begin();
- for (; it_g != g.end(); ++it_g)
- infoMsg.AddString("group", (*it_g).c_str());
- // Resources
- gloox::RosterItem::ResourceMap::const_iterator rit
- = (*it).second->resources().begin();
- for (; rit != (*it).second->resources().end(); ++rit)
- infoMsg.AddString("resource", (*rit).first.c_str());
- // Store contact info message to be sent later
- msgs.push_back(infoMsg);
- }
- // Send server based contact list
- _SendMessage(&contactListMsg);
- // Contact list and vCard request
- std::list<BMessage>::iterator msgsIt;
- for (msgsIt = msgs.begin(); msgsIt != msgs.end(); ++msgsIt) {
- BMessage msg = (*msgsIt);
- const char* jid = msg.FindString("user_id");
- _SendMessage(&msg);
- fVCardManager->fetchVCard(gloox::JID(jid), this);
- }
- // This is a safe spot to say "READY", since this is called immediately
- // after logging in, whether the user has friends in the roster or not―
- // especially since loading all the users from the roster can take a while.
- BMessage readyMsg(IM_MESSAGE);
- readyMsg.AddInt32("im_what", IM_PROTOCOL_READY);
- _SendMessage(&readyMsg);
- }
- void
- JabberHandler::handleMessageSession(gloox::MessageSession* session)
- {
- // Delete previous session
- if (fSession)
- fClient->disposeMessageSession(fSession);
- fSession = session;
- // Register message handler
- fSession->registerMessageHandler(this);
- // Message event filter
- gloox::MessageEventFilter* messageFilter
- = new gloox::MessageEventFilter(fSession);
- messageFilter->registerMessageEventHandler(this);
- // Chat state filter
- gloox::ChatStateFilter* chatFilter
- = new gloox::ChatStateFilter(fSession);
- chatFilter->registerChatStateHandler(this);
- }
- void
- JabberHandler::handleMessage(const gloox::Message& m, gloox::MessageSession*)
- {
- // Only chat messages are handled now
- if (m.subtype() != gloox::Message::Chat)
- return;
- // We need a body
- if (m.body() == "")
- return;
- _EnsureUserChat(m.from().bare().c_str());
- // Notify that a chat message was received
- BMessage msg(IM_MESSAGE);
- msg.AddString("user_id", m.from().bare().c_str());
- msg.AddString("chat_id", m.from().bare().c_str());
- msg.AddInt32("im_what", IM_MESSAGE_RECEIVED);
- if (m.subject() != "")
- msg.AddString("subject", m.subject().c_str());
- msg.AddString("body", m.body().c_str());
- _SendMessage(&msg);
- }
- void
- JabberHandler::handleMessageEvent(const gloox::JID& from, gloox::MessageEventType event)
- {
- }
- void
- JabberHandler::handleChatState(const gloox::JID& from, gloox::ChatStateType state)
- {
- // We're interested only in some states
- if (state == gloox::ChatStateActive || state == gloox::ChatStateInvalid)
- return;
- _EnsureUserChat(from.bare().c_str());
- BMessage msg(IM_MESSAGE);
- msg.AddString("user_id", from.bare().c_str());
- msg.AddString("chat_id", from.bare().c_str());
- switch (state) {
- case gloox::ChatStateComposing:
- msg.AddInt32("im_what", IM_ROOM_PARTICIPANT_STARTED_TYPING);
- break;
- case gloox::ChatStatePaused:
- msg.AddInt32("im_what", IM_ROOM_PARTICIPANT_STOPPED_TYPING);
- break;
- case gloox::ChatStateGone:
- // TODO
- break;
- default:
- break;
- }
- _SendMessage(&msg);
- }
- void
- JabberHandler::handleMUCParticipantPresence(gloox::MUCRoom *room,
- const gloox::MUCRoomParticipant participant,
- const gloox::Presence &presence)
- {
- // participant.flags, particpiant.role
- // 0-0 (left), 0-* (joined/rolechange)
- gloox::MUCRoomRole role = participant.role;
- gloox::MUCRoomAffiliation aff = participant.affiliation;
- const char* nick = participant.nick->resource().c_str();
- BString user_id;
- BString chat_id = _MUCChatId(room);
- bool isSelf = _MUCUserId(chat_id, nick, &user_id);
- if (chat_id.IsEmpty() == true || user_id.IsEmpty() == true)
- return;
- if (participant.flags & gloox::UserSelf) {
- if ((participant.flags & gloox::UserNickChanged)
- || (participant.flags & gloox::UserNickAssigned))
- {
- BMessage nickChanged(IM_MESSAGE);
- nickChanged.AddInt32("im_what", IM_OWN_NICKNAME_SET);
- nickChanged.AddString("user_name", participant.newNick.c_str());
- _SendMessage(&nickChanged);
- fNick = participant.newNick.c_str();
- }
- else {
- int im_what = IM_ROOM_JOINED;
- if (presence.presence() == 5)
- im_what = IM_ROOM_LEFT;
- BMessage joinedMsg(IM_MESSAGE);
- joinedMsg.AddInt32("im_what", im_what);
- joinedMsg.AddString("chat_id", chat_id);
- _SendMessage(&joinedMsg);
- _RoleChangedMsg(chat_id, user_id, role, aff);
- }
- return;
- }
- _StatusSetMsg(user_id.String(), presence.presence(), presence.status().c_str(), "");
- // If unavailable (disconnected/left chat)
- if (presence.presence() == 5) {
- _UserLeftMsg(chat_id, participant);
- return;
- }
- BMessage joinMsg(IM_MESSAGE);
- joinMsg.AddInt32("im_what", IM_ROOM_PARTICIPANT_JOINED);
- joinMsg.AddString("user_id", user_id);
- joinMsg.AddString("user_name", nick);
- joinMsg.AddString("chat_id", chat_id);
- _SendMessage(&joinMsg);
- _RoleChangedMsg(chat_id, user_id, role, aff);
- }
- void
- JabberHandler::handleMUCMessage(gloox::MUCRoom *room, const gloox::Message &m,
- bool priv)
- {
- BString user_id;
- BString chat_id = _MUCChatId(room);
- bool isSelf = _MUCUserId(chat_id, m.from().resource().c_str(), &user_id);
- if (chat_id.IsEmpty() == true || user_id.IsEmpty() == true)
- return;
- int32 im_what = IM_MESSAGE_RECEIVED;
- // We need a body
- if (m.body() == "")
- return;
- // If sent from own user, then IM_MESSAGE_SENT
- if (isSelf == true)
- im_what = IM_MESSAGE_SENT;
- // when() is only nonzero when sending backdated messages (logs)
- if (m.when() != 0)
- im_what = IM_LOGS_RECEIVED;
- // Notify that a chat message was received
- BMessage msg(IM_MESSAGE);
- msg.AddInt32("im_what", im_what);
- msg.AddString("user_id", user_id);
- msg.AddString("chat_id", chat_id);
- if (m.subject() != "")
- msg.AddString("subject", m.subject().c_str());
- msg.AddString("body", m.body().c_str());
- _SendMessage(&msg);
- }
- bool
- JabberHandler::handleMUCRoomCreation(gloox::MUCRoom* room)
- {
- BMessage msg(IM_MESSAGE);
- msg.AddInt32("im_what", IM_ROOM_CREATED);
- msg.AddString("chat_id", _MUCChatId(room));
- _SendMessage(&msg);
- return true;
- }
- void
- JabberHandler::handleMUCSubject(gloox::MUCRoom *room, const std::string &nick,
- const std::string &subject)
- {
- BString user_id;
- BString chat_id = _MUCChatId(room);
- bool isSelf = _MUCUserId(chat_id, nick.c_str(), &user_id);
- if (chat_id.IsEmpty() == true)
- return;
- BMessage msg(IM_MESSAGE);
- msg.AddInt32("im_what", IM_ROOM_SUBJECT_SET);
- msg.AddString("subject", subject.c_str());
- msg.AddString("chat_id", chat_id);
- if (user_id.IsEmpty() == false)
- msg.AddString("user_id", user_id);
- _SendMessage(&msg);
- }
- void
- JabberHandler::handleMUCInviteDecline(gloox::MUCRoom *room, const gloox::JID &invitee,
- const std::string &reason)
- {
- }
- void
- JabberHandler::handleMUCError(gloox::MUCRoom *room, gloox::StanzaError error)
- {
- HandleStanzaError(error);
- }
- void
- JabberHandler::handleMUCInfo(gloox::MUCRoom *room, int features,
- const std::string &name, const gloox::DataForm *infoForm)
- {
- BString chat_id = _MUCChatId(room);
- BMessage metadata(IM_MESSAGE);
- metadata.AddInt32("im_what", IM_ROOM_METADATA);
- metadata.AddString("chat_id", chat_id);
- metadata.AddString("chat_name", name.c_str());
- metadata.AddInt32("room_default_flags", 0 | ROOM_AUTOJOIN
- | ROOM_LOG_LOCALLY | ROOM_POPULATE_LOGS | ROOM_NOTIFY_DM);
- metadata.AddInt32("room_disallowed_flags", 0 | ROOM_AUTOCREATE);
- _SendMessage(&metadata);
- }
- void
- JabberHandler::handleMUCItems(gloox::MUCRoom *room, const gloox::Disco::ItemList &items)
- {
- BString chat_id = _MUCChatId(room);
- BStringList nicks;
- BStringList ids;
- if (chat_id.IsEmpty() == true)
- return;
- for (auto item: items) {
- BString nick = item->jid().resource().c_str();
- nicks.Add(nick);
- // Unless it's the user, derive ID from room resource
- if (fNick != nick) {
- BString user_id(chat_id);
- user_id << "/" << nick;
- ids.Add(user_id);
- }
- else
- ids.Add(BString(fJid.bare().c_str()));
- }
- BMessage msg(IM_MESSAGE);
- msg.AddStrings("user_id", ids);
- msg.AddStrings("user_name", nicks);
- msg.AddString("chat_id", chat_id);
- msg.AddInt32("im_what", IM_ROOM_PARTICIPANTS);
- _SendMessage(&msg);
- }
- void
- JabberHandler::handleMUCConfigList(gloox::MUCRoom* room, const gloox::MUCListItemList &items,
- gloox::MUCOperation operation)
- {
- }
- void
- JabberHandler::handleMUCConfigForm(gloox::MUCRoom* room, const gloox::DataForm &form)
- {
- }
- void
- JabberHandler::handleMUCConfigResult(gloox::MUCRoom* room, bool success,
- gloox::MUCOperation operation)
- {
- }
- void
- JabberHandler::handleMUCRequest(gloox::MUCRoom* room, const gloox::DataForm &form)
- {
- }
- void
- JabberHandler::handleItemAdded(const gloox::JID&)
- {
- }
- void
- JabberHandler::handleItemSubscribed(const gloox::JID&)
- {
- }
- void
- JabberHandler::handleItemUnsubscribed(const gloox::JID&)
- {
- }
- void
- JabberHandler::handleItemRemoved(const gloox::JID&)
- {
- }
- void
- JabberHandler::handleItemUpdated(const gloox::JID&)
- {
- }
- void
- JabberHandler::handleRosterPresence(const gloox::RosterItem& item,
- const std::string& resource,
- gloox::Presence::PresenceType type,
- const std::string& presenceMsg)
- {
- _StatusSetMsg(item.jidJID().full().c_str(), type, presenceMsg.c_str(),
- resource.c_str());
- }
- void
- JabberHandler::handleSelfPresence(const gloox::RosterItem& item, const std::string&,
- gloox::Presence::PresenceType type,
- const std::string& presenceMsg)
- {
- BMessage msg(IM_MESSAGE);
- msg.AddInt32("im_what", IM_OWN_CONTACT_INFO);
- msg.AddString("protocol", Signature());
- msg.AddString("user_id", item.jidJID().full().c_str());
- msg.AddString("user_name", fNick.String());
- msg.AddInt32("subscription", item.subscription());
- msg.AddInt32("status", _GlooxStatusToApp(type));
- msg.AddString("message", presenceMsg.c_str());
- // Groups
- gloox::StringList g = item.groups();
- gloox::StringList::const_iterator it_g = g.begin();
- for (; it_g != g.end(); ++it_g)
- msg.AddString("group", (*it_g).c_str());
- // Resources
- gloox::RosterItem::ResourceMap::const_iterator rit
- = item.resources().begin();
- for (; rit != item.resources().end(); ++rit)
- msg.AddString("resource", (*rit).first.c_str());
- _SendMessage(&msg);
- }
- bool
- JabberHandler::handleSubscriptionRequest(const gloox::JID&, const std::string&)
- {
- return true;
- }
- bool
- JabberHandler::handleUnsubscriptionRequest(const gloox::JID&, const std::string&)
- {
- return true;
- }
- void
- JabberHandler::handleNonrosterPresence(const gloox::Presence&)
- {
- }
- void
- JabberHandler::handleRosterError(const gloox::IQ&)
- {
- }
- void
- JabberHandler::handleLog(gloox::LogLevel level, gloox::LogArea,
- const std::string& msg)
- {
- if (level >= gloox::LogLevelWarning)
- std::cout << msg << std::endl;
- }
- void
- JabberHandler::handleVCard(const gloox::JID& jid, const gloox::VCard* card)
- {
- if (!card)
- return;
- // Throttles updates to your own VCard― ime some servers spam for no reason
- if (jid.bare() == fJid.bare()) {
- bigtime_t last = fLastOwnVCard;
- fLastOwnVCard = time(NULL);
- if (fLastOwnVCard - last < 60)
- return;
- }
- gloox::VCard::Name name = card->name();
- gloox::VCard::Photo photo = card->photo();
- BString nick(card->nickname().c_str());
- gloox::RosterItem* item = fClient->rosterManager()->getRosterItem(jid);
- if (item != NULL)
- nick = item->name().c_str();
- std::string fullName = name.family + " " + name.given;
- BMessage msg(IM_MESSAGE);
- msg.AddInt32("im_what", IM_EXTENDED_CONTACT_INFO);
- msg.AddString("user_id", jid.bare().c_str());
- msg.AddString("user_name", nick);
- msg.AddString("family_name", name.family.c_str());
- msg.AddString("given_name", name.given.c_str());
- msg.AddString("middle_name", name.middle.c_str());
- msg.AddString("prefix", name.prefix.c_str());
- msg.AddString("suffix", name.suffix.c_str());
- msg.AddString("full_name", fullName.c_str());
- _SendMessage(&msg);
- // Return if there's no avatar icon
- if (!photo.binval.c_str())
- return;
- if (_SetupAvatarCache() == B_OK)
- // Cache avatar icon and notify the change
- _CacheAvatar(jid.bare().c_str(), photo.binval.c_str(),
- photo.binval.length());
- }
- void
- JabberHandler::handleVCardResult(gloox::VCardHandler::VCardContext context,
- const gloox::JID& jid,
- gloox::StanzaError)
- {
- //if (context == gloox::VCardHandler::FetchVCard)
- //else
- }
- OurClient::OurClient(const gloox::JID jid, const char* password)
- :
- gloox::Client(jid, password)
- {
- }
- void
- OurClient::handleTag(gloox::Tag* tag)
- {
- if (DEBUG_ENABLED)
- std::cerr << "Tag\t" << tag->xml() << std::endl;
- gloox::Client::handleTag(tag);
- }
- InviteHandler::InviteHandler(gloox::ClientBase* client, JabberHandler* handler)
- :
- gloox::MUCInvitationHandler(client),
- fHandler(handler)
- {
- }
- void
- InviteHandler::handleMUCInvitation(const gloox::JID& room, const gloox::JID& from,
- const std::string& reason, const std::string& body,
- const std::string& password, bool cont,
- const std::string& thread)
- {
- std::string chat_name = room.resource().c_str();
- BString chat_id = room.full().c_str();
- if (chat_name.empty() == true)
- chat_name = chat_id.String();
- if (password.empty() == false)
- chat_id << "#" << password.c_str();
- BMessage invite(IM_MESSAGE);
- invite.AddInt32("im_what", IM_ROOM_INVITE_RECEIVED);
- invite.AddString("chat_id", chat_id);
- invite.AddString("chat_name", chat_name.c_str());
- invite.AddString("user_id", from.bare().c_str());
- if (reason.empty() == false)
- invite.AddString("body", reason.c_str());
- invite.AddString("protocol", fHandler->Signature());
- fHandler->MessengerInterface()->SendMessage(new BMessage(invite));
- }
|