JabberHandler.cpp 53 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054
  1. /*
  2. * Copyright 2010, Pier Luigi Fiorini. All rights reserved.
  3. * Copyright 2021, Jaidyn Levesque. All rights reserved.
  4. * Distributed under the terms of the GPL v2 License.
  5. *
  6. * Authors:
  7. * Pier Luigi Fiorini, pierluigi.fiorini@gmail.com
  8. * Jaidyn Levesque, jadedctrl@teknik.io
  9. */
  10. #include <iostream>
  11. #include <Catalog.h>
  12. #include <Directory.h>
  13. #include <Entry.h>
  14. #include <File.h>
  15. #include <FindDirectory.h>
  16. #include <List.h>
  17. #include <StringList.h>
  18. #include <libsupport/SHA1.h>
  19. #include <ChatProtocolMessages.h>
  20. #include <Flags.h>
  21. #include <Role.h>
  22. #include <gloox/chatstatefilter.h>
  23. #include <gloox/messageeventfilter.h>
  24. #include <gloox/mucroom.h>
  25. #include "JabberHandler.h"
  26. #undef B_TRANSLATION_CONTEXT
  27. #define B_TRANSLATION_CONTEXT "JabberHandler"
  28. static status_t
  29. connect_thread(void* data)
  30. {
  31. JabberHandler* handler = (JabberHandler*)data;
  32. if (!handler)
  33. return B_BAD_VALUE;
  34. gloox::Client* client = handler->Client();
  35. if (!client)
  36. return B_BAD_VALUE;
  37. gloox::ConnectionError e;
  38. while ((e = client->recv(10000000)) == gloox::ConnNoError);
  39. if (e != gloox::ConnUserDisconnected)
  40. handler->HandleConnectionError(e);
  41. return B_OK;
  42. }
  43. JabberHandler::JabberHandler()
  44. :
  45. fClient(NULL),
  46. fVCardManager(NULL),
  47. fSession(NULL),
  48. fLastOwnVCard(0)
  49. {
  50. fAvatars = new BList();
  51. }
  52. JabberHandler::~JabberHandler()
  53. {
  54. Shutdown();
  55. BString* item = NULL;
  56. for (int32 i = 0; (item = (BString*)fAvatars->ItemAt(i)); i++)
  57. delete item;
  58. delete fAvatars;
  59. }
  60. status_t
  61. JabberHandler::Init(ChatProtocolMessengerInterface* messenger)
  62. {
  63. fServerMessenger = messenger;
  64. return B_OK;
  65. }
  66. status_t
  67. JabberHandler::Process(BMessage* msg)
  68. {
  69. if (msg->what != IM_MESSAGE)
  70. return B_ERROR;
  71. int32 im_what = 0;
  72. msg->FindInt32("im_what", &im_what);
  73. switch (im_what) {
  74. case IM_SET_OWN_STATUS:
  75. {
  76. int32 status = msg->FindInt32("status");
  77. BString status_msg = msg->FindString("message");
  78. switch (status) {
  79. case STATUS_ONLINE:
  80. // Log in if we still need to
  81. resume_thread(fRecvThread);
  82. break;
  83. case STATUS_OFFLINE:
  84. kill_thread(fRecvThread);
  85. break;
  86. default:
  87. break;
  88. }
  89. break;
  90. }
  91. case IM_SET_OWN_NICKNAME:
  92. {
  93. const char* nick = msg->FindString("user_name");
  94. if (nick != NULL)
  95. for (int i = 0; i < fRooms.CountItems(); i++)
  96. fRooms.ValueAt(i)->setNick(nick);
  97. break;
  98. }
  99. case IM_SEND_MESSAGE:
  100. {
  101. const char* id = msg->FindString("chat_id");
  102. const char* subject = msg->FindString("subject");
  103. const char* body = msg->FindString("body");
  104. gloox::MUCRoom* room = fRooms.ValueFor(id);
  105. if (!id || !body)
  106. return B_ERROR;
  107. // Send JabberHandler message
  108. gloox::Message jm(gloox::Message::Chat, gloox::JID(id),
  109. body, (subject ? subject : gloox::EmptyString));
  110. if (room != NULL) {
  111. room->send(body);
  112. break;
  113. }
  114. else
  115. fClient->send(jm);
  116. // If non-MUC, tell Caya we actually sent the message
  117. // (An MUC should echo the message back to us later, see
  118. // handleMUCMessage)
  119. _MessageSent(id, subject, body);
  120. break;
  121. }
  122. case IM_CREATE_CHAT:
  123. {
  124. const char* user_id = msg->FindString("user_id");
  125. // TODO: Contact validation, make sure permssion is granted
  126. if (!user_id)
  127. return B_ERROR;
  128. _EnsureUserChat(user_id);
  129. _ChatCreatedMsg(user_id);
  130. break;
  131. }
  132. case IM_CREATE_ROOM:
  133. {
  134. BString chat_id;
  135. if (msg->FindString("chat_id", &chat_id) != B_OK)
  136. break;
  137. _JoinRoom(chat_id);
  138. break;
  139. }
  140. case IM_JOIN_ROOM:
  141. {
  142. BString chat_id;
  143. if (msg->FindString("chat_id", &chat_id) == B_OK)
  144. _JoinRoom(chat_id.String());
  145. break;
  146. }
  147. case IM_LEAVE_ROOM:
  148. {
  149. BString chat_id = msg->FindString("chat_id");
  150. gloox::MUCRoom* room = fRooms.ValueFor(chat_id);
  151. // MUCs are special, one-on-ones we can just drop
  152. if (room != NULL)
  153. room->leave();
  154. // We've gotta let Caya know!
  155. BMessage left(IM_MESSAGE);
  156. left.AddInt32("im_what", IM_ROOM_LEFT);
  157. left.AddString("chat_id", chat_id);
  158. _SendMessage(&left);
  159. break;
  160. }
  161. case IM_ROOM_INVITE_ACCEPT:
  162. {
  163. BString chat_id;
  164. if (msg->FindString("chat_id", &chat_id) != B_OK)
  165. break;
  166. BStringList splitAtPassword;
  167. chat_id.Split("#", false, splitAtPassword);
  168. chat_id = splitAtPassword.StringAt(0);
  169. _JoinRoom(chat_id.String());
  170. break;
  171. }
  172. case IM_ROOM_SEND_INVITE:
  173. {
  174. BString chat_id = msg->FindString("chat_id");
  175. gloox::MUCRoom* room = fRooms.ValueFor(chat_id);
  176. BString user_id;
  177. if (room == NULL || msg->FindString("user_id", &user_id) != B_OK)
  178. break;
  179. room->invite(gloox::JID(user_id.String()), "");
  180. break;
  181. }
  182. case IM_GET_ROOM_PARTICIPANTS:
  183. {
  184. BString chat_id = msg->FindString("chat_id");
  185. gloox::MUCRoom* room = fRooms.ValueFor(chat_id);
  186. if (room != NULL)
  187. room->getRoomItems();
  188. else if (fUserChats.HasString(chat_id) == true) {
  189. BMessage users(IM_MESSAGE);
  190. users.AddInt32("im_what", IM_ROOM_PARTICIPANTS);
  191. users.AddString("user_id", chat_id);
  192. }
  193. break;
  194. }
  195. case IM_GET_ROOM_METADATA:
  196. {
  197. BString chat_id = msg->FindString("chat_id");
  198. gloox::MUCRoom* room = fRooms.ValueFor(chat_id);
  199. if (room != NULL)
  200. room->getRoomInfo();
  201. if (fUserChats.HasString(chat_id) == true)
  202. {
  203. BMessage metadata(IM_MESSAGE);
  204. metadata.AddInt32("im_what", IM_ROOM_METADATA);
  205. metadata.AddString("chat_id", chat_id);
  206. metadata.AddInt32("room_default_flags", 0 | ROOM_LOG_LOCALLY
  207. | ROOM_POPULATE_LOGS | ROOM_NOTIFY_DM);
  208. metadata.AddInt32("room_disallowed_flags", 0 | ROOM_AUTOJOIN
  209. | ROOM_AUTOCREATE);
  210. _SendMessage(&metadata);
  211. }
  212. break;
  213. }
  214. case IM_SET_ROOM_SUBJECT:
  215. {
  216. BString chat_id = msg->FindString("chat_id");
  217. gloox::MUCRoom* room = fRooms.ValueFor(chat_id);
  218. if (room != NULL)
  219. room->setSubject(msg->GetString("subject", ""));
  220. break;
  221. }
  222. case IM_GET_EXTENDED_CONTACT_INFO:
  223. {
  224. BString user_id;
  225. if (msg->FindString("user_id", &user_id) == B_OK)
  226. fVCardManager->fetchVCard(gloox::JID(user_id.String()), this);
  227. break;
  228. }
  229. case IM_ROSTER_ADD_CONTACT:
  230. {
  231. BString user_name = msg->FindString("user_name");
  232. BString user_id;
  233. if (msg->FindString("user_id", &user_id) != B_OK)
  234. break;
  235. fClient->rosterManager()->add(gloox::JID(user_id.String()),
  236. user_name.String(), gloox::StringList());
  237. fClient->rosterManager()->subscribe(gloox::JID(user_id.String()),
  238. user_name.String());
  239. fClient->rosterManager()->synchronize();
  240. break;
  241. }
  242. case IM_ROSTER_REMOVE_CONTACT:
  243. {
  244. BString user_id;
  245. if (msg->FindString("user_id", &user_id) != B_OK)
  246. break;
  247. fClient->rosterManager()->remove(gloox::JID(user_id.String()));
  248. fClient->rosterManager()->unsubscribe(gloox::JID(user_id.String()));
  249. fClient->rosterManager()->synchronize();
  250. BMessage rm(IM_MESSAGE);
  251. rm.AddInt32("im_what", IM_ROSTER_CONTACT_REMOVED);
  252. rm.AddString("user_id", user_id);
  253. _SendMessage(&rm);
  254. break;
  255. }
  256. case IM_ROSTER_EDIT_CONTACT:
  257. {
  258. BString user_id;
  259. BString user_name = msg->FindString("user_name");
  260. if (msg->FindString("user_id", &user_id) != B_OK)
  261. break;
  262. gloox::JID jid(user_id.String());
  263. gloox::RosterItem* item =
  264. fClient->rosterManager()->getRosterItem(jid);
  265. if (item != NULL && user_name.IsEmpty() == false) {
  266. item->setName(user_name.String());
  267. fClient->rosterManager()->synchronize();
  268. }
  269. break;
  270. }
  271. case IM_ROOM_KICK_PARTICIPANT:
  272. case IM_ROOM_BAN_PARTICIPANT:
  273. case IM_ROOM_UNBAN_PARTICIPANT:
  274. case IM_ROOM_MUTE_PARTICIPANT:
  275. case IM_ROOM_UNMUTE_PARTICIPANT:
  276. _MUCModeration(msg);
  277. break;
  278. default:
  279. return B_ERROR;
  280. }
  281. return B_OK;
  282. }
  283. status_t
  284. JabberHandler::Shutdown()
  285. {
  286. if (fVCardManager)
  287. fVCardManager->cancelVCardOperations(this);
  288. if (fClient)
  289. fClient->disposeMessageSession(fSession);
  290. kill_thread(fRecvThread);
  291. return B_OK;
  292. }
  293. void
  294. JabberHandler::SetAddOnPath(BPath path)
  295. {
  296. fPath = path;
  297. }
  298. BPath
  299. JabberHandler::AddOnPath()
  300. {
  301. return fPath;
  302. }
  303. void
  304. JabberHandler::SetName(const char* name)
  305. {
  306. fName = name;
  307. }
  308. const char*
  309. JabberHandler::GetName()
  310. {
  311. return fName.String();
  312. }
  313. BObjectList<BMessage>
  314. JabberHandler::Commands()
  315. {
  316. return BObjectList<BMessage>();
  317. }
  318. BObjectList<BMessage>
  319. JabberHandler::ChatPopUpItems()
  320. {
  321. return BObjectList<BMessage>();
  322. }
  323. BObjectList<BMessage>
  324. JabberHandler::UserPopUpItems()
  325. {
  326. return BObjectList<BMessage>();
  327. }
  328. BObjectList<BMessage>
  329. JabberHandler::MenuBarItems()
  330. {
  331. return BObjectList<BMessage>();
  332. }
  333. status_t
  334. JabberHandler::UpdateSettings(BMessage* msg)
  335. {
  336. const char* username = msg->FindString("username");
  337. const char* password = msg->FindString("password");
  338. const char* server = msg->FindString("server");
  339. const char* resource = msg->FindString("resource");
  340. // Sanity check
  341. if (!username || !password || !resource)
  342. return B_ERROR;
  343. // Store settings
  344. fUsername = username;
  345. fNick = username;
  346. fPassword = password;
  347. fServer = server;
  348. fResource = resource;
  349. fPort = 5222;
  350. // Give the add-on a change to override settings
  351. OverrideSettings();
  352. // Compose JID
  353. BString jid = ComposeJID();
  354. fJid.setJID(jid.String());
  355. // Register our client
  356. fClient = new OurClient(fJid, fPassword.String());
  357. fClient->setServer(fServer.String());
  358. if (fPort > 0)
  359. fClient->setPort(fPort);
  360. fClient->registerConnectionListener(this);
  361. fClient->registerMessageSessionHandler(this);
  362. fClient->registerMUCInvitationHandler(new InviteHandler(fClient, this));
  363. fClient->rosterManager()->registerRosterListener(this);
  364. fClient->disco()->setVersion("Chat-O-Matic", VERSION);
  365. fClient->disco()->setIdentity("client", "chat-o-matic");
  366. fClient->logInstance().registerLogHandler(gloox::LogLevelDebug,
  367. gloox::LogAreaAll, this);
  368. // Register vCard manager
  369. fVCardManager = new gloox::VCardManager(fClient);
  370. // Connect to the server
  371. fClient->connect(false);
  372. // Read data from another thread
  373. fRecvThread = spawn_thread(connect_thread, "connect_thread",
  374. B_NORMAL_PRIORITY, (void*)this);
  375. if (fRecvThread < B_OK)
  376. return B_ERROR;
  377. return B_OK;
  378. }
  379. uint32
  380. JabberHandler::GetEncoding()
  381. {
  382. return 0xffff;
  383. }
  384. ChatProtocolMessengerInterface*
  385. JabberHandler::MessengerInterface() const
  386. {
  387. return fServerMessenger;
  388. }
  389. gloox::Client*
  390. JabberHandler::Client() const
  391. {
  392. return fClient;
  393. }
  394. void
  395. JabberHandler::HandleConnectionError(gloox::ConnectionError& e)
  396. {
  397. #undef B_TRANSLATION_CONTEXT
  398. #define B_TRANSLATION_CONTEXT "JabberHandler ― Connection errors"
  399. // Handle error
  400. BMessage errMsg(IM_ERROR);
  401. switch (e) {
  402. case gloox::ConnStreamError:
  403. {
  404. #undef B_TRANSLATION_CONTEXT
  405. #define B_TRANSLATION_CONTEXT "JabberHandler ― Connection stream errors"
  406. gloox::StreamError streamError = fClient->streamError();
  407. errMsg.AddString("error", B_TRANSLATE("Bad or malformed XML stream."));
  408. switch (streamError) {
  409. case gloox::StreamErrorBadFormat:
  410. errMsg.AddString("detail", B_TRANSLATE("The entity has "
  411. "sent XML that cannot be processed"));
  412. break;
  413. case gloox::StreamErrorBadNamespacePrefix:
  414. errMsg.AddString("detail", B_TRANSLATE("The entity has "
  415. "sent a namespace prefix which is not supported, "
  416. "or has sent no namespace prefix on an element "
  417. "that requires such prefix."));
  418. break;
  419. case gloox::StreamErrorConflict:
  420. errMsg.AddString("detail", B_TRANSLATE("The server is "
  421. "closing the active stream for this entity "
  422. "because a new stream has been initiated that "
  423. "conflicts with the existing stream."));
  424. break;
  425. case gloox::StreamErrorConnectionTimeout:
  426. errMsg.AddString("detail", B_TRANSLATE("The entity has "
  427. "not generated any traffic over the stream for "
  428. "some period of time."));
  429. break;
  430. case gloox::StreamErrorHostGone:
  431. errMsg.AddString("detail", B_TRANSLATE("The host initially "
  432. "used corresponds to a hostname that is no longer "
  433. "hosted by the server."));
  434. break;
  435. case gloox::StreamErrorHostUnknown:
  436. errMsg.AddString("detail", B_TRANSLATE("The host initially "
  437. "used does not correspond to a hostname that is "
  438. "hosted by the server."));
  439. break;
  440. case gloox::StreamErrorImproperAddressing:
  441. errMsg.AddString("detail", B_TRANSLATE("A stanza sent "
  442. "between two servers lacks a 'to' or 'from' "
  443. "attribute (or the attribute has no value."));
  444. break;
  445. case gloox::StreamErrorInternalServerError:
  446. errMsg.AddString("detail", B_TRANSLATE("The server has "
  447. "experienced a misconfiguration or an "
  448. "otherwise-undefined internal error that prevents "
  449. "it from servicing the stream."));
  450. break;
  451. case gloox::StreamErrorInvalidFrom:
  452. errMsg.AddString("detail", B_TRANSLATE("The JID or "
  453. "hostname provided in a 'from' address does not "
  454. "match an authorized JID or validated domain "
  455. "negotiation between servers via SASL or dialback, "
  456. "or between a client and a server via "
  457. "authentication and resource binding."));
  458. break;
  459. case gloox::StreamErrorInvalidId:
  460. errMsg.AddString("detail", B_TRANSLATE("The stream ID or "
  461. "dialback ID is invalid or does not match and ID "
  462. "previously provdided."));
  463. break;
  464. case gloox::StreamErrorInvalidNamespace:
  465. errMsg.AddString("detail", B_TRANSLATE("The streams "
  466. "namespace name is something other than "
  467. "\"http://etherx.jabber.org/streams\" or the "
  468. "dialback namespace name is something other than "
  469. "\"jabber:server:dialback\"."));
  470. break;
  471. case gloox::StreamErrorInvalidXml:
  472. errMsg.AddString("detail", B_TRANSLATE("The entity has "
  473. "sent invalid XML over the stream to a server that "
  474. "performs validation."));
  475. break;
  476. case gloox::StreamErrorNotAuthorized:
  477. errMsg.AddString("detail", B_TRANSLATE("The entity has "
  478. "attempted to send data before the stream has been "
  479. "authenticated, or otherwise is not authorized to "
  480. "perform an action related to stream negotiation; "
  481. "the receiving entity must not process the "
  482. "offending stanza before sending the stream "
  483. "error."));
  484. break;
  485. case gloox::StreamErrorPolicyViolation:
  486. errMsg.AddString("detail", B_TRANSLATE("The entity has "
  487. "violated some local service policy; the server "
  488. "may choose to specify the policy in the <text/> "
  489. "element or an application-specific condition "
  490. "element."));
  491. break;
  492. case gloox::StreamErrorRemoteConnectionFailed:
  493. errMsg.AddString("detail", B_TRANSLATE("The server is "
  494. "unable to properly connect to a remote entity "
  495. "that is required for authentication."));
  496. break;
  497. case gloox::StreamErrorResourceConstraint:
  498. errMsg.AddString("detail", B_TRANSLATE("The server lacks "
  499. "the system resources necessary to service the "
  500. "stream."));
  501. break;
  502. case gloox::StreamErrorRestrictedXml:
  503. errMsg.AddString("detail", B_TRANSLATE("The entity has "
  504. "attempted to send restricted XML features such as "
  505. "a comment, processing instruction, DTD, entity "
  506. "reference or unescaped character."));
  507. break;
  508. case gloox::StreamErrorSeeOtherHost:
  509. errMsg.AddString("detail", B_TRANSLATE("The server will "
  510. "not provide service to the initiating entity but "
  511. "is redirecting traffic to another host; the "
  512. "server should specify the alternate hostname or "
  513. "IP address (which MUST be a valid domain "
  514. "identifier) as the XML characted data of the "
  515. "<see-other-host/> element."));
  516. break;
  517. case gloox::StreamErrorSystemShutdown:
  518. errMsg.AddString("detail", B_TRANSLATE("The server is "
  519. "being shut down and all active streams are being "
  520. "closed."));
  521. break;
  522. case gloox::StreamErrorUndefinedCondition:
  523. errMsg.AddString("detail", B_TRANSLATE("The error "
  524. "condition is not one of those defined by the "
  525. "other condition in this list; this error "
  526. "condition should be used only in conjunction with "
  527. "an application-specific condition."));
  528. break;
  529. case gloox::StreamErrorUnsupportedEncoding:
  530. errMsg.AddString("detail", B_TRANSLATE("The initiating "
  531. "entity has encoded the stream in an encoding "
  532. "that is not supported by the server."));
  533. break;
  534. case gloox::StreamErrorUnsupportedStanzaType:
  535. errMsg.AddString("detail", B_TRANSLATE("The initiating "
  536. "entity has sent a first-level child of the stream "
  537. "that is not supported by the server."));
  538. break;
  539. case gloox::StreamErrorUnsupportedVersion:
  540. errMsg.AddString("detail", B_TRANSLATE("The value of the "
  541. "'version' attribute provided by the initiating "
  542. "entity in the stream header specifies a version "
  543. "of XMPP that is not supported by the server; the "
  544. "server may specify the version(s) it supports in "
  545. "the <text/> element."));
  546. break;
  547. case gloox::StreamErrorXmlNotWellFormed:
  548. errMsg.AddString("detail", B_TRANSLATE("The initiating "
  549. "entity has sent XML that is not well-formed as "
  550. "defined by XML."));
  551. break;
  552. default:
  553. break;
  554. }
  555. break;
  556. }
  557. case gloox::ConnStreamVersionError:
  558. errMsg.AddString("detail", B_TRANSLATE("The incoming stream's "
  559. "version is not supported."));
  560. break;
  561. case gloox::ConnStreamClosed:
  562. errMsg.AddString("detail", B_TRANSLATE("The stream has been closed "
  563. "by the server."));
  564. break;
  565. case gloox::ConnProxyAuthRequired:
  566. errMsg.AddString("detail", B_TRANSLATE("The HTTP/SOCKS5 proxy "
  567. "requires authentication."));
  568. break;
  569. case gloox::ConnProxyAuthFailed:
  570. errMsg.AddString("detail", B_TRANSLATE("HTTP/SOCKS5 proxy "
  571. "authentication failed."));
  572. break;
  573. case gloox::ConnProxyNoSupportedAuth:
  574. errMsg.AddString("detail", B_TRANSLATE("The HTTP/SOCKS5 proxy "
  575. "requires an unsupported authentication mechanism."));
  576. break;
  577. case gloox::ConnIoError:
  578. errMsg.AddString("detail", B_TRANSLATE("Input/output error."));
  579. break;
  580. case gloox::ConnParseError:
  581. errMsg.AddString("detail", B_TRANSLATE("A XML parse error "
  582. "occurred."));
  583. break;
  584. case gloox::ConnConnectionRefused:
  585. errMsg.AddString("detail", B_TRANSLATE("The connection was refused "
  586. "by the server on the socket level."));
  587. break;
  588. case gloox::ConnDnsError:
  589. errMsg.AddString("detail", B_TRANSLATE("Server's hostname "
  590. "resolution failed."));
  591. break;
  592. case gloox::ConnOutOfMemory:
  593. errMsg.AddString("detail", B_TRANSLATE("Out of memory."));
  594. break;
  595. case gloox::ConnTlsFailed:
  596. errMsg.AddString("detail", B_TRANSLATE("The server's certificate "
  597. "could not be verified or the TLS handshake did not "
  598. "complete successfully."));
  599. break;
  600. case gloox::ConnTlsNotAvailable:
  601. errMsg.AddString("detail", B_TRANSLATE("The server didn't offer "
  602. "TLS while it was set to be required, or TLS was not "
  603. "compiled in."));
  604. break;
  605. case gloox::ConnCompressionFailed:
  606. errMsg.AddString("detail", B_TRANSLATE("Negotiating or "
  607. "initializing compression failed."));
  608. break;
  609. case gloox::ConnAuthenticationFailed:
  610. {
  611. #undef B_TRANSLATION_CONTEXT
  612. #define B_TRANSLATION_CONTEXT "JabberHandler ― Connection authentication errors"
  613. gloox::AuthenticationError authError = fClient->authError();
  614. errMsg.AddString("error", B_TRANSLATE("Authentication failed. "
  615. "Username or password wrong or account does not "
  616. "exist."));
  617. switch (authError) {
  618. case gloox::SaslAborted:
  619. errMsg.AddString("detail", B_TRANSLATE("The receiving "
  620. "entity acknowledges an <abort/> element sent by "
  621. "initiating entity; sent in reply to the <abort/> "
  622. "element."));
  623. break;
  624. case gloox::SaslIncorrectEncoding:
  625. errMsg.AddString("detail", B_TRANSLATE("The data provided "
  626. "by the initiating entity could not be processed "
  627. "because the base64 encoding is incorrect."));
  628. break;
  629. case gloox::SaslInvalidAuthzid:
  630. errMsg.AddString("detail", B_TRANSLATE("The authid "
  631. "provided by the initiating entity is invalid, "
  632. "either because it is incorrectly formatted or "
  633. "because the initiating entity does not have "
  634. "permissions to authorize that ID; sent in reply "
  635. "to a <response/> element or an <auth/> element "
  636. "with initial response data."));
  637. break;
  638. case gloox::SaslInvalidMechanism:
  639. errMsg.AddString("detail", B_TRANSLATE("The initiating "
  640. "element did not provide a mechanism or requested "
  641. "a mechanism that is not supported by the "
  642. "receiving entity; sent in reply to an <auth/> "
  643. "element."));
  644. break;
  645. case gloox::SaslMalformedRequest:
  646. errMsg.AddString("detail", B_TRANSLATE("The request is "
  647. "malformed (e.g., the <auth/> element includes an "
  648. "initial response but the mechanism does not "
  649. "allow that); sent in reply to an <abort/>, "
  650. "<auth/>, <challenge/>, or <response/> element."));
  651. break;
  652. case gloox::SaslMechanismTooWeak:
  653. errMsg.AddString("detail", B_TRANSLATE("The mechanism "
  654. "requested by the initiating entity is weaker "
  655. "than server policy permits for that initiating "
  656. "entity; sent in reply to a <response/> element or "
  657. "an <auth/> element with initial response data."));
  658. break;
  659. case gloox::SaslNotAuthorized:
  660. errMsg.AddString("detail", B_TRANSLATE("The authentication "
  661. "failed because the initiating entity did not "
  662. "provide valid credentials (this includes but is "
  663. "not limited to the case of an unknown username); "
  664. "sent in reply to a <response/> element or an "
  665. "<auth/> element with initial response data."));
  666. break;
  667. case gloox::SaslTemporaryAuthFailure:
  668. errMsg.AddString("detail", B_TRANSLATE("The authentication "
  669. "failed because of a temporary error condition "
  670. "within the receiving entity; sent in reply to an "
  671. "<auth/> element or <response/> element."));
  672. break;
  673. case gloox::NonSaslConflict:
  674. errMsg.AddString("detail", B_TRANSLATE("Resource conflict, "
  675. "see XEP-0078."));
  676. break;
  677. case gloox::NonSaslNotAcceptable:
  678. errMsg.AddString("detail", B_TRANSLATE("Required "
  679. "information not provided, see XEP-0078."));
  680. break;
  681. case gloox::NonSaslNotAuthorized:
  682. errMsg.AddString("detail", B_TRANSLATE("Incorrect "
  683. "credentials."));
  684. break;
  685. default:
  686. break;
  687. }
  688. break;
  689. }
  690. case gloox::ConnNotConnected: {
  691. BMessage disconnect(IM_MESSAGE);
  692. disconnect.AddInt32("im_what", IM_PROTOCOL_DISABLE);
  693. _SendMessage(&disconnect);
  694. break;
  695. }
  696. default:
  697. break;
  698. }
  699. _SendMessage(&errMsg);
  700. }
  701. void
  702. JabberHandler::HandleStanzaError(gloox::StanzaError error)
  703. {
  704. #undef B_TRANSLATION_CONTEXT
  705. #define B_TRANSLATION_CONTEXT "JabberHandler ― Stanza errors"
  706. BMessage errMsg(IM_ERROR);
  707. errMsg.AddString("error", B_TRANSLATE("Stanza-related error"));
  708. BString detail;
  709. switch (error)
  710. {
  711. case gloox::StanzaErrorBadRequest:
  712. detail = B_TRANSLATE("The sender has sent XML that is malformed or "
  713. "that cannot be processed.");
  714. break;
  715. case gloox::StanzaErrorConflict:
  716. detail = B_TRANSLATE("Access cannot be granted because an existing "
  717. "resource or session exists with the same name or address.");
  718. break;
  719. case gloox::StanzaErrorFeatureNotImplemented:
  720. detail = B_TRANSLATE("This feature hasn't been implemented by the "
  721. "recipient or by the server.");
  722. break;
  723. case gloox::StanzaErrorForbidden:
  724. detail = B_TRANSLATE("You don't have permssion to do this.");
  725. break;
  726. case gloox::StanzaErrorGone:
  727. detail = B_TRANSLATE("The recipient or server can no longer be "
  728. "contacted at this address. Try again later, or with a "
  729. "different address.");
  730. break;
  731. case gloox::StanzaErrorInternalServerError:
  732. detail = B_TRANSLATE("The server could not process the stanza "
  733. "because of a misconfiguration or an otherwise-undefined "
  734. "internal server error.");
  735. break;
  736. case gloox::StanzaErrorItemNotFound:
  737. detail = B_TRANSLATE("The addressed JID or item requested cannot "
  738. "be found.");
  739. break;
  740. case gloox::StanzaErrorJidMalformed:
  741. detail = B_TRANSLATE("An invalid XMPP address or identifier was "
  742. "given. If you can, please try a different one.");
  743. break;
  744. case gloox::StanzaErrorNotAcceptable:
  745. detail = B_TRANSLATE("The server or user refuses to accept this, "
  746. "because some criteria hasn't been met (e.g., a local policy "
  747. "regarding acceptable words in messages).");
  748. break;
  749. case gloox::StanzaErrorNotAllowed:
  750. detail = B_TRANSLATE("You aren't allowed to do this by the server "
  751. "or recepient.");
  752. break;
  753. case gloox::StanzaErrorNotAuthorized:
  754. detail = B_TRANSLATE("You need to be properily authenticated "
  755. "before doing this.");
  756. case gloox::StanzaErrorNotModified:
  757. detail = B_TRANSLATE("The item requested has not changed since it "
  758. "was last requested.");
  759. case gloox::StanzaErrorPaymentRequired:
  760. detail = B_TRANSLATE("The server refuses to offer service, because "
  761. "payment is required.");
  762. break;
  763. case gloox::StanzaErrorRecipientUnavailable:
  764. detail = B_TRANSLATE("The recipient is temporarily unavailable.");
  765. break;
  766. case gloox::StanzaErrorRedirect:
  767. detail = B_TRANSLATE("The recipient or server is redirecting "
  768. "requests for this information to another entity, usually "
  769. "temporarily.");
  770. break;
  771. case gloox::StanzaErrorRegistrationRequired:
  772. detail = B_TRANSLATE("You can't do this before registration! Be "
  773. "sure your finished registering for your account.");
  774. break;
  775. case gloox::StanzaErrorRemoteServerNotFound:
  776. detail = B_TRANSLATE("That user's server doesn't exist.");
  777. break;
  778. case gloox::StanzaErrorRemoteServerTimeout:
  779. detail = B_TRANSLATE("Connection to that user's server has timed "
  780. "out.");
  781. break;
  782. case gloox::StanzaErrorResourceConstraint:
  783. detail = B_TRANSLATE("The server or recipient are too busy right "
  784. "now; try again later.");
  785. break;
  786. case gloox::StanzaErrorServiceUnavailable:
  787. detail = B_TRANSLATE("The server or recipient don't provide this "
  788. "service.");
  789. break;
  790. case gloox::StanzaErrorSubscribtionRequired:
  791. detail = B_TRANSLATE("You can't access this unless you are "
  792. "subscribed.");
  793. break;
  794. }
  795. errMsg.AddString("detail", detail);
  796. _SendMessage(&errMsg);
  797. }
  798. void
  799. JabberHandler::_SendMessage(BMessage* msg)
  800. {
  801. // Skip invalid messages
  802. if (!msg)
  803. return;
  804. msg->AddString("protocol", Signature());
  805. fServerMessenger->SendMessage(msg);
  806. }
  807. void
  808. JabberHandler::_Notify(notification_type type, const char* title, const char* message)
  809. {
  810. BMessage msg(IM_MESSAGE);
  811. msg.AddInt32("im_what", IM_NOTIFICATION);
  812. msg.AddInt32("type", (int32)type);
  813. msg.AddString("title", title);
  814. msg.AddString("message", message);
  815. _SendMessage(&msg);
  816. }
  817. void
  818. JabberHandler::_NotifyProgress(const char* title, const char* message, float progress)
  819. {
  820. BMessage msg(IM_MESSAGE);
  821. msg.AddInt32("im_what", IM_PROGRESS);
  822. msg.AddString("title", title);
  823. msg.AddString("message", message);
  824. msg.AddFloat("progress", progress);
  825. _SendMessage(&msg);
  826. }
  827. void
  828. JabberHandler::_MessageSent(const char* id, const char* subject,
  829. const char* body)
  830. {
  831. BMessage msg(IM_MESSAGE);
  832. msg.AddInt32("im_what", IM_MESSAGE_SENT);
  833. msg.AddString("user_id", fJid.bare().c_str());
  834. msg.AddString("chat_id", id);
  835. msg.AddString("subject", subject);
  836. msg.AddString("body", body);
  837. _SendMessage(&msg);
  838. }
  839. void
  840. JabberHandler::_ChatCreatedMsg(const char* id)
  841. {
  842. BMessage msg(IM_MESSAGE);
  843. msg.AddInt32("im_what", IM_CHAT_CREATED);
  844. msg.AddString("chat_id", id);
  845. msg.AddString("user_id", id);
  846. _SendMessage(&msg);
  847. }
  848. void
  849. JabberHandler::_RoleChangedMsg(BString chat_id, BString user_id,
  850. gloox::MUCRoomRole role, gloox::MUCRoomAffiliation aff)
  851. {
  852. BMessage roleMsg(IM_MESSAGE);
  853. roleMsg.AddInt32("im_what", IM_ROOM_ROLECHANGED);
  854. roleMsg.AddString("user_id", user_id);
  855. roleMsg.AddString("chat_id", chat_id);
  856. roleMsg.AddString("role_title", _RoleTitle(role, aff));
  857. roleMsg.AddInt32("role_perms", _RolePerms(role, aff));
  858. roleMsg.AddInt32("role_priority", _RolePriority(role, aff));
  859. _SendMessage(&roleMsg);
  860. }
  861. void
  862. JabberHandler::_UserLeftMsg(BString chat_id, gloox::MUCRoomParticipant participant)
  863. {
  864. BString user_id;
  865. const char* nick = participant.nick->resource().c_str();
  866. bool isSelf = _MUCUserId(chat_id, nick, &user_id);
  867. if (user_id.IsEmpty() == true)
  868. return;
  869. int32 im_what = IM_ROOM_PARTICIPANT_LEFT;
  870. int flags = participant.flags;
  871. if (flags & gloox::UserBanned)
  872. im_what = IM_ROOM_PARTICIPANT_BANNED;
  873. else if (flags & gloox::UserKicked)
  874. im_what = IM_ROOM_PARTICIPANT_KICKED;
  875. BMessage leftMsg(IM_MESSAGE);
  876. leftMsg.AddInt32("im_what", im_what);
  877. leftMsg.AddString("chat_id", chat_id);
  878. leftMsg.AddString("user_id", user_id);
  879. leftMsg.AddString("user_name", nick);
  880. if (participant.reason.empty() == false)
  881. leftMsg.AddString("body", participant.reason.c_str());
  882. _SendMessage(&leftMsg);
  883. }
  884. void
  885. JabberHandler::_StatusSetMsg(const char* user_id, gloox::Presence::PresenceType type,
  886. const char* message, const char* resource)
  887. {
  888. BMessage msg(IM_MESSAGE);
  889. msg.AddInt32("im_what", IM_USER_STATUS_SET);
  890. msg.AddString("user_id", user_id);
  891. msg.AddInt32("status", _GlooxStatusToApp(type));
  892. if (BString(resource).IsEmpty() == false)
  893. msg.AddString("resource", resource);
  894. if (BString(message).IsEmpty() == false)
  895. msg.AddString("message", message);
  896. _SendMessage(&msg);
  897. }
  898. void
  899. JabberHandler::_EnsureUserChat(const char* chat_id)
  900. {
  901. if (fUserChats.HasString(BString(chat_id)) == false)
  902. fUserChats.Add(BString(chat_id));
  903. }
  904. status_t
  905. JabberHandler::_SetupAvatarCache()
  906. {
  907. if (fAvatarCachePath.InitCheck() == B_OK)
  908. return B_OK;
  909. BPath path;
  910. if (find_directory(B_SYSTEM_TEMP_DIRECTORY, &path) != B_OK)
  911. return B_ERROR;
  912. path.Append(GetName());
  913. if (create_directory(path.Path(), 0755) != B_OK)
  914. return B_ERROR;
  915. fCachePath = path;
  916. path.Append("avatar-cache");
  917. BFile file(path.Path(), B_READ_ONLY);
  918. fAvatarCache.Unflatten(&file);
  919. fAvatarCachePath = path;
  920. return B_OK;
  921. }
  922. status_t
  923. JabberHandler::_SaveAvatarCache()
  924. {
  925. if (fAvatarCachePath.InitCheck() != B_OK)
  926. return B_ERROR;
  927. BFile file(fAvatarCachePath.Path(), B_CREATE_FILE | B_WRITE_ONLY | B_ERASE_FILE);
  928. return fAvatarCache.Flatten(&file);
  929. }
  930. void
  931. JabberHandler::_CacheAvatar(const char* id, const char* binimage, size_t length)
  932. {
  933. if (!id || !binimage || length <= 0)
  934. return;
  935. // Calculate avatar hash
  936. CSHA1 s1;
  937. char hash[256];
  938. s1.Reset();
  939. s1.Update((uchar*)binimage, length);
  940. s1.Final();
  941. s1.ReportHash(hash, CSHA1::REPORT_HEX);
  942. BString sha1;
  943. sha1.SetTo(hash, 256);
  944. BString oldSha1;
  945. if (fAvatarCache.FindString(id, &oldSha1) != B_OK || oldSha1 == "" || sha1 != oldSha1) {
  946. // Replace old hash and save cache
  947. fAvatarCache.RemoveName(id);
  948. fAvatarCache.AddString(id, sha1);
  949. _SaveAvatarCache();
  950. if (oldSha1 != "") {
  951. BPath path(fCachePath);
  952. path.Append(oldSha1);
  953. // Remove old image file
  954. BEntry entry(path.Path());
  955. entry.Remove();
  956. // Remove old hash from the list
  957. BString* item = NULL;
  958. for (int32 i = 0; (item = (BString*)fAvatars->ItemAt(i)); i++) {
  959. if (item->Compare(oldSha1) == 0) {
  960. fAvatars->RemoveItem(item);
  961. break;
  962. }
  963. }
  964. }
  965. }
  966. // Determine file path
  967. BPath path(fCachePath);
  968. path.Append(sha1);
  969. BEntry entry(path.Path());
  970. if (!entry.Exists()) {
  971. // Save to file
  972. BFile file(path.Path(), B_CREATE_FILE | B_WRITE_ONLY | B_ERASE_FILE);
  973. file.Write(binimage, length);
  974. }
  975. // Do we need to notify the app?
  976. bool found = false;
  977. BString* item = NULL;
  978. for (int32 i = 0; (item = (BString*)fAvatars->ItemAt(i)); i++) {
  979. if (item->Compare(sha1) == 0) {
  980. found = true;
  981. break;
  982. }
  983. }
  984. if (!found) {
  985. // Add new hash to the list if needed
  986. fAvatars->AddItem(new BString(sha1));
  987. // Notify Caya that the avatar has changed
  988. _AvatarChanged(id, path.Path());
  989. }
  990. }
  991. void
  992. JabberHandler::_AvatarChanged(const char* id, const char* filename)
  993. {
  994. entry_ref ref;
  995. if (get_ref_for_path(filename, &ref) != B_OK)
  996. return;
  997. BMessage msg(IM_MESSAGE);
  998. if (fJid.bare() == id)
  999. msg.AddInt32("im_what", IM_OWN_AVATAR_SET);
  1000. else {
  1001. msg.AddInt32("im_what", IM_USER_AVATAR_SET);
  1002. msg.AddString("user_id", id);
  1003. }
  1004. msg.AddRef("ref", &ref);
  1005. _SendMessage(&msg);
  1006. }
  1007. UserStatus
  1008. JabberHandler::_GlooxStatusToApp(gloox::Presence::PresenceType type)
  1009. {
  1010. switch (type) {
  1011. case gloox::Presence::Available:
  1012. case gloox::Presence::Chat:
  1013. return STATUS_ONLINE;
  1014. case gloox::Presence::Away:
  1015. return STATUS_AWAY;
  1016. case gloox::Presence::XA:
  1017. return STATUS_CUSTOM_STATUS;
  1018. case gloox::Presence::DND:
  1019. return STATUS_DO_NOT_DISTURB;
  1020. case gloox::Presence::Unavailable:
  1021. return STATUS_OFFLINE;
  1022. default:
  1023. break;
  1024. }
  1025. return STATUS_OFFLINE;
  1026. }
  1027. BString
  1028. JabberHandler::_MUCChatId(gloox::MUCRoom* room)
  1029. {
  1030. BString chat_id(room->name().c_str());
  1031. chat_id << "@" << room->service().c_str();
  1032. BStringList parts;
  1033. chat_id.Split("/", false, parts);
  1034. return parts.StringAt(0);
  1035. }
  1036. bool
  1037. JabberHandler::_MUCUserId(BString chat_id, const char* nick, BString* id)
  1038. {
  1039. BString chat(chat_id);
  1040. chat << "/" << nick;
  1041. // If sent from own user, use normal ID
  1042. if (nick == fNick) {
  1043. *id = fJid.bare().c_str();
  1044. return true;
  1045. }
  1046. *id = chat;
  1047. return false;
  1048. }
  1049. void
  1050. JabberHandler::_JoinRoom(const char* chat_id)
  1051. {
  1052. BString join_id(chat_id);
  1053. join_id << "/" << fNick;
  1054. gloox::MUCRoom* room = fRooms.ValueFor(chat_id);
  1055. if (room == NULL)
  1056. room = new gloox::MUCRoom(fClient, gloox::JID(join_id.String()), this, this);
  1057. room->join();
  1058. fRooms.AddItem(BString(chat_id), room);
  1059. }
  1060. void
  1061. JabberHandler::_MUCModeration(BMessage* msg)
  1062. {
  1063. BString chat_id = msg->FindString("chat_id");
  1064. BString user_id;
  1065. BString body = msg->FindString("body");
  1066. gloox::MUCRoom* room = fRooms.ValueFor(chat_id);
  1067. if (room == NULL || msg->FindString("user_id", &user_id) != B_OK)
  1068. return;
  1069. std::string nick = gloox::JID(user_id.String()).resource();
  1070. switch (msg->FindInt32("im_what"))
  1071. {
  1072. case IM_ROOM_KICK_PARTICIPANT:
  1073. room->kick(nick, body.String());
  1074. break;
  1075. case IM_ROOM_BAN_PARTICIPANT:
  1076. room->ban(nick, body.String());
  1077. break;
  1078. case IM_ROOM_MUTE_PARTICIPANT:
  1079. room->revokeVoice(nick, body.String());
  1080. break;
  1081. case IM_ROOM_UNMUTE_PARTICIPANT:
  1082. room->grantVoice(nick, body.String());
  1083. break;
  1084. }
  1085. }
  1086. const char*
  1087. JabberHandler::_RoleTitle(gloox::MUCRoomRole role, gloox::MUCRoomAffiliation aff)
  1088. {
  1089. #undef B_TRANSLATION_CONTEXT
  1090. #define B_TRANSLATION_CONTEXT "JabberHandler ― User roles"
  1091. switch (role)
  1092. {
  1093. case gloox::RoleVisitor:
  1094. return B_TRANSLATE("Visitor");
  1095. case gloox::RoleParticipant:
  1096. return B_TRANSLATE("Member");
  1097. case gloox::RoleModerator:
  1098. if (aff == gloox::AffiliationOwner)
  1099. return B_TRANSLATE("Owner");
  1100. return B_TRANSLATE("Moderator");
  1101. }
  1102. return B_TRANSLATE("Invalid");
  1103. }
  1104. int32
  1105. JabberHandler::_RolePerms(gloox::MUCRoomRole role, gloox::MUCRoomAffiliation aff)
  1106. {
  1107. switch (role)
  1108. {
  1109. case gloox::RoleVisitor:
  1110. return 0 | PERM_READ | PERM_NICK;
  1111. case gloox::RoleParticipant:
  1112. return 0 | PERM_READ | PERM_WRITE | PERM_ROOM_SUBJECT;
  1113. case gloox::RoleModerator: {
  1114. int32 perm = 0 | PERM_READ | PERM_WRITE | PERM_ROOM_SUBJECT
  1115. | PERM_KICK | PERM_MUTE;
  1116. if (aff == gloox::AffiliationOwner)
  1117. perm = perm | PERM_ROLECHANGE | PERM_BAN;
  1118. return perm;
  1119. }
  1120. }
  1121. return 0;
  1122. }
  1123. int32
  1124. JabberHandler::_RolePriority(gloox::MUCRoomRole role, gloox::MUCRoomAffiliation aff)
  1125. {
  1126. switch (role)
  1127. {
  1128. case gloox::RoleParticipant:
  1129. return 1;
  1130. case gloox::RoleModerator:
  1131. if (aff == gloox::AffiliationOwner)
  1132. return 3;
  1133. return 2;
  1134. }
  1135. return 0;
  1136. }
  1137. BMessage
  1138. JabberHandler::_SettingsTemplate(const char* username, bool serverOption)
  1139. {
  1140. #undef B_TRANSLATION_CONTEXT
  1141. #define B_TRANSLATION_CONTEXT "JabberHandler ― Settings template"
  1142. BMessage stemplate('IMst');
  1143. BMessage usernameText;
  1144. usernameText.AddString("name", "username");
  1145. usernameText.AddString("description", username);
  1146. usernameText.AddString("error", B_TRANSLATE("You can't log into an account "
  1147. "without a username.\nPlease fill in your username for the given "
  1148. "server."));
  1149. usernameText.AddInt32("type", 'CSTR');
  1150. stemplate.AddMessage("setting", &usernameText);
  1151. BMessage passwordText;
  1152. passwordText.AddString("name", "password");
  1153. passwordText.AddString("description", B_TRANSLATE("Password:"));
  1154. passwordText.AddString("error", B_TRANSLATE("You can't log into an account "
  1155. "without a password.\nPlease fill in your password for the given "
  1156. "account."));
  1157. passwordText.AddInt32("type", 'CSTR');
  1158. passwordText.AddBool("is_secret", true);
  1159. stemplate.AddMessage("setting", &passwordText);
  1160. BMessage serverText;
  1161. serverText.AddString("name", "server");
  1162. serverText.AddString("description", B_TRANSLATE("Server:"));
  1163. serverText.AddString("error", B_TRANSLATE("You can't add an account "
  1164. "without a server.\nPlease add a valid XMPP server."));
  1165. serverText.AddInt32("type", 'CSTR');
  1166. if (serverOption == true)
  1167. stemplate.AddMessage("setting", &serverText);
  1168. BMessage resourceText;
  1169. resourceText.AddString("name", "resource");
  1170. resourceText.AddString("description", B_TRANSLATE("Resource:"));
  1171. resourceText.AddInt32("type", 'CSTR');
  1172. resourceText.AddString("default", "Chat-O-Matic");
  1173. resourceText.AddString("error", B_TRANSLATE("You can't add an account "
  1174. "without a resource.\nDon't worry― it can be whatever string you "
  1175. "want."));
  1176. stemplate.AddMessage("setting", &resourceText);
  1177. return stemplate;
  1178. }
  1179. BMessage
  1180. JabberHandler::_RoomTemplate()
  1181. {
  1182. #undef B_TRANSLATION_CONTEXT
  1183. #define B_TRANSLATION_CONTEXT "JabberHandler ― Room template"
  1184. BMessage stemplate('IMst');
  1185. BMessage roomIdentifier;
  1186. roomIdentifier.AddString("name", "chat_id");
  1187. roomIdentifier.AddString("description", B_TRANSLATE("Room ID:"));
  1188. roomIdentifier.AddString("error", B_TRANSLATE("You can't have a room "
  1189. "without a JID!\nUse the \"name@server\" format."));
  1190. roomIdentifier.AddInt32("type", 'CSTR');
  1191. stemplate.AddMessage("setting", &roomIdentifier);
  1192. return stemplate;
  1193. }
  1194. BMessage
  1195. JabberHandler::_RosterTemplate()
  1196. {
  1197. #undef B_TRANSLATION_CONTEXT
  1198. #define B_TRANSLATION_CONTEXT "JabberHandler ― Roster template"
  1199. BMessage stemplate('IMst');
  1200. BMessage user_id;
  1201. user_id.AddString("name", "user_id");
  1202. user_id.AddString("description", B_TRANSLATE("User ID:"));
  1203. user_id.AddString("error", B_TRANSLATE("You can't befriend an IDless "
  1204. "miscreant!\nPlease use the \"name@server\" format."));
  1205. user_id.AddInt32("type", 'CSTR');
  1206. stemplate.AddMessage("setting", &user_id);
  1207. BMessage user_name;
  1208. user_name.AddString("name", "user_name");
  1209. user_name.AddString("description", B_TRANSLATE("Nickname:"));
  1210. user_name.AddInt32("type", 'CSTR');
  1211. stemplate.AddMessage("setting", &user_name);
  1212. return stemplate;
  1213. }
  1214. /***********************************************************************
  1215. * gloox callbacks
  1216. **********************************************************************/
  1217. void
  1218. JabberHandler::onConnect()
  1219. {
  1220. // We are online
  1221. BMessage msg(IM_MESSAGE);
  1222. msg.AddInt32("im_what", IM_OWN_STATUS_SET);
  1223. msg.AddInt32("status", STATUS_ONLINE);
  1224. _SendMessage(&msg);
  1225. fVCardManager->fetchVCard(fJid, this);
  1226. }
  1227. void
  1228. JabberHandler::onDisconnect(gloox::ConnectionError e)
  1229. {
  1230. // We are offline
  1231. BMessage msg(IM_MESSAGE);
  1232. msg.AddInt32("im_what", IM_OWN_STATUS_SET);
  1233. msg.AddInt32("status", STATUS_OFFLINE);
  1234. _SendMessage(&msg);
  1235. if (e == gloox::ConnNoError) {
  1236. // Notify our offline status
  1237. BString content(fUsername);
  1238. content << " has logged out!";
  1239. _Notify(B_INFORMATION_NOTIFICATION, "Disconnected",
  1240. content.String());
  1241. return;
  1242. }
  1243. // Handle error
  1244. HandleConnectionError(e);
  1245. }
  1246. bool
  1247. JabberHandler::onTLSConnect(const gloox::CertInfo& info)
  1248. {
  1249. return true;
  1250. }
  1251. void
  1252. JabberHandler::onResourceBindError(const gloox::Error* error)
  1253. {
  1254. }
  1255. void
  1256. JabberHandler::handleRoster(const gloox::Roster& roster)
  1257. {
  1258. std::list<BMessage> msgs;
  1259. BMessage contactListMsg(IM_MESSAGE);
  1260. contactListMsg.AddInt32("im_what", IM_ROSTER);
  1261. gloox::Roster::const_iterator it = roster.begin();
  1262. for (; it != roster.end(); ++it) {
  1263. const char* jid = (*it).second->jidJID().full().c_str();
  1264. const char* name = (*it).second->name().c_str();
  1265. int32 subscription = (*it).second->subscription();
  1266. // Add jid to the server based contact list message
  1267. contactListMsg.AddString("user_id", jid);
  1268. // Contact information message
  1269. BMessage infoMsg(IM_MESSAGE);
  1270. infoMsg.AddInt32("im_what", IM_CONTACT_INFO);
  1271. infoMsg.AddString("user_id", jid);
  1272. infoMsg.AddString("user_name", name);
  1273. infoMsg.AddInt32("status", STATUS_OFFLINE);
  1274. // Groups
  1275. gloox::StringList g = (*it).second->groups();
  1276. gloox::StringList::const_iterator it_g = g.begin();
  1277. for (; it_g != g.end(); ++it_g)
  1278. infoMsg.AddString("group", (*it_g).c_str());
  1279. // Resources
  1280. gloox::RosterItem::ResourceMap::const_iterator rit
  1281. = (*it).second->resources().begin();
  1282. for (; rit != (*it).second->resources().end(); ++rit)
  1283. infoMsg.AddString("resource", (*rit).first.c_str());
  1284. // Store contact info message to be sent later
  1285. msgs.push_back(infoMsg);
  1286. }
  1287. // Send server based contact list
  1288. _SendMessage(&contactListMsg);
  1289. // Contact list and vCard request
  1290. std::list<BMessage>::iterator msgsIt;
  1291. for (msgsIt = msgs.begin(); msgsIt != msgs.end(); ++msgsIt) {
  1292. BMessage msg = (*msgsIt);
  1293. const char* jid = msg.FindString("user_id");
  1294. _SendMessage(&msg);
  1295. fVCardManager->fetchVCard(gloox::JID(jid), this);
  1296. }
  1297. // This is a safe spot to say "READY", since this is called immediately
  1298. // after logging in, whether the user has friends in the roster or not―
  1299. // especially since loading all the users from the roster can take a while.
  1300. BMessage readyMsg(IM_MESSAGE);
  1301. readyMsg.AddInt32("im_what", IM_PROTOCOL_READY);
  1302. _SendMessage(&readyMsg);
  1303. }
  1304. void
  1305. JabberHandler::handleMessageSession(gloox::MessageSession* session)
  1306. {
  1307. // Delete previous session
  1308. if (fSession)
  1309. fClient->disposeMessageSession(fSession);
  1310. fSession = session;
  1311. // Register message handler
  1312. fSession->registerMessageHandler(this);
  1313. // Message event filter
  1314. gloox::MessageEventFilter* messageFilter
  1315. = new gloox::MessageEventFilter(fSession);
  1316. messageFilter->registerMessageEventHandler(this);
  1317. // Chat state filter
  1318. gloox::ChatStateFilter* chatFilter
  1319. = new gloox::ChatStateFilter(fSession);
  1320. chatFilter->registerChatStateHandler(this);
  1321. }
  1322. void
  1323. JabberHandler::handleMessage(const gloox::Message& m, gloox::MessageSession*)
  1324. {
  1325. // Only chat messages are handled now
  1326. if (m.subtype() != gloox::Message::Chat)
  1327. return;
  1328. // We need a body
  1329. if (m.body() == "")
  1330. return;
  1331. _EnsureUserChat(m.from().bare().c_str());
  1332. // Notify that a chat message was received
  1333. BMessage msg(IM_MESSAGE);
  1334. msg.AddString("user_id", m.from().bare().c_str());
  1335. msg.AddString("chat_id", m.from().bare().c_str());
  1336. msg.AddInt32("im_what", IM_MESSAGE_RECEIVED);
  1337. if (m.subject() != "")
  1338. msg.AddString("subject", m.subject().c_str());
  1339. msg.AddString("body", m.body().c_str());
  1340. _SendMessage(&msg);
  1341. }
  1342. void
  1343. JabberHandler::handleMessageEvent(const gloox::JID& from, gloox::MessageEventType event)
  1344. {
  1345. }
  1346. void
  1347. JabberHandler::handleChatState(const gloox::JID& from, gloox::ChatStateType state)
  1348. {
  1349. // We're interested only in some states
  1350. if (state == gloox::ChatStateActive || state == gloox::ChatStateInvalid)
  1351. return;
  1352. _EnsureUserChat(from.bare().c_str());
  1353. BMessage msg(IM_MESSAGE);
  1354. msg.AddString("user_id", from.bare().c_str());
  1355. msg.AddString("chat_id", from.bare().c_str());
  1356. switch (state) {
  1357. case gloox::ChatStateComposing:
  1358. msg.AddInt32("im_what", IM_ROOM_PARTICIPANT_STARTED_TYPING);
  1359. break;
  1360. case gloox::ChatStatePaused:
  1361. msg.AddInt32("im_what", IM_ROOM_PARTICIPANT_STOPPED_TYPING);
  1362. break;
  1363. case gloox::ChatStateGone:
  1364. // TODO
  1365. break;
  1366. default:
  1367. break;
  1368. }
  1369. _SendMessage(&msg);
  1370. }
  1371. void
  1372. JabberHandler::handleMUCParticipantPresence(gloox::MUCRoom *room,
  1373. const gloox::MUCRoomParticipant participant,
  1374. const gloox::Presence &presence)
  1375. {
  1376. // participant.flags, particpiant.role
  1377. // 0-0 (left), 0-* (joined/rolechange)
  1378. gloox::MUCRoomRole role = participant.role;
  1379. gloox::MUCRoomAffiliation aff = participant.affiliation;
  1380. const char* nick = participant.nick->resource().c_str();
  1381. BString user_id;
  1382. BString chat_id = _MUCChatId(room);
  1383. bool isSelf = _MUCUserId(chat_id, nick, &user_id);
  1384. if (chat_id.IsEmpty() == true || user_id.IsEmpty() == true)
  1385. return;
  1386. if (participant.flags & gloox::UserSelf) {
  1387. if ((participant.flags & gloox::UserNickChanged)
  1388. || (participant.flags & gloox::UserNickAssigned))
  1389. {
  1390. BMessage nickChanged(IM_MESSAGE);
  1391. nickChanged.AddInt32("im_what", IM_OWN_NICKNAME_SET);
  1392. nickChanged.AddString("user_name", participant.newNick.c_str());
  1393. _SendMessage(&nickChanged);
  1394. fNick = participant.newNick.c_str();
  1395. }
  1396. else {
  1397. int im_what = IM_ROOM_JOINED;
  1398. if (presence.presence() == 5)
  1399. im_what = IM_ROOM_LEFT;
  1400. BMessage joinedMsg(IM_MESSAGE);
  1401. joinedMsg.AddInt32("im_what", im_what);
  1402. joinedMsg.AddString("chat_id", chat_id);
  1403. _SendMessage(&joinedMsg);
  1404. _RoleChangedMsg(chat_id, user_id, role, aff);
  1405. }
  1406. return;
  1407. }
  1408. _StatusSetMsg(user_id.String(), presence.presence(), presence.status().c_str(), "");
  1409. // If unavailable (disconnected/left chat)
  1410. if (presence.presence() == 5) {
  1411. _UserLeftMsg(chat_id, participant);
  1412. return;
  1413. }
  1414. BMessage joinMsg(IM_MESSAGE);
  1415. joinMsg.AddInt32("im_what", IM_ROOM_PARTICIPANT_JOINED);
  1416. joinMsg.AddString("user_id", user_id);
  1417. joinMsg.AddString("user_name", nick);
  1418. joinMsg.AddString("chat_id", chat_id);
  1419. _SendMessage(&joinMsg);
  1420. _RoleChangedMsg(chat_id, user_id, role, aff);
  1421. }
  1422. void
  1423. JabberHandler::handleMUCMessage(gloox::MUCRoom *room, const gloox::Message &m,
  1424. bool priv)
  1425. {
  1426. BString user_id;
  1427. BString chat_id = _MUCChatId(room);
  1428. bool isSelf = _MUCUserId(chat_id, m.from().resource().c_str(), &user_id);
  1429. if (chat_id.IsEmpty() == true || user_id.IsEmpty() == true)
  1430. return;
  1431. int32 im_what = IM_MESSAGE_RECEIVED;
  1432. // We need a body
  1433. if (m.body() == "")
  1434. return;
  1435. // If sent from own user, then IM_MESSAGE_SENT
  1436. if (isSelf == true)
  1437. im_what = IM_MESSAGE_SENT;
  1438. // when() is only nonzero when sending backdated messages (logs)
  1439. if (m.when() != 0)
  1440. im_what = IM_LOGS_RECEIVED;
  1441. // Notify that a chat message was received
  1442. BMessage msg(IM_MESSAGE);
  1443. msg.AddInt32("im_what", im_what);
  1444. msg.AddString("user_id", user_id);
  1445. msg.AddString("chat_id", chat_id);
  1446. if (m.subject() != "")
  1447. msg.AddString("subject", m.subject().c_str());
  1448. msg.AddString("body", m.body().c_str());
  1449. _SendMessage(&msg);
  1450. }
  1451. bool
  1452. JabberHandler::handleMUCRoomCreation(gloox::MUCRoom* room)
  1453. {
  1454. BMessage msg(IM_MESSAGE);
  1455. msg.AddInt32("im_what", IM_ROOM_CREATED);
  1456. msg.AddString("chat_id", _MUCChatId(room));
  1457. _SendMessage(&msg);
  1458. return true;
  1459. }
  1460. void
  1461. JabberHandler::handleMUCSubject(gloox::MUCRoom *room, const std::string &nick,
  1462. const std::string &subject)
  1463. {
  1464. BString user_id;
  1465. BString chat_id = _MUCChatId(room);
  1466. bool isSelf = _MUCUserId(chat_id, nick.c_str(), &user_id);
  1467. if (chat_id.IsEmpty() == true)
  1468. return;
  1469. BMessage msg(IM_MESSAGE);
  1470. msg.AddInt32("im_what", IM_ROOM_SUBJECT_SET);
  1471. msg.AddString("subject", subject.c_str());
  1472. msg.AddString("chat_id", chat_id);
  1473. if (user_id.IsEmpty() == false)
  1474. msg.AddString("user_id", user_id);
  1475. _SendMessage(&msg);
  1476. }
  1477. void
  1478. JabberHandler::handleMUCInviteDecline(gloox::MUCRoom *room, const gloox::JID &invitee,
  1479. const std::string &reason)
  1480. {
  1481. }
  1482. void
  1483. JabberHandler::handleMUCError(gloox::MUCRoom *room, gloox::StanzaError error)
  1484. {
  1485. HandleStanzaError(error);
  1486. }
  1487. void
  1488. JabberHandler::handleMUCInfo(gloox::MUCRoom *room, int features,
  1489. const std::string &name, const gloox::DataForm *infoForm)
  1490. {
  1491. BString chat_id = _MUCChatId(room);
  1492. BMessage metadata(IM_MESSAGE);
  1493. metadata.AddInt32("im_what", IM_ROOM_METADATA);
  1494. metadata.AddString("chat_id", chat_id);
  1495. metadata.AddString("chat_name", name.c_str());
  1496. metadata.AddInt32("room_default_flags", 0 | ROOM_AUTOJOIN
  1497. | ROOM_LOG_LOCALLY | ROOM_POPULATE_LOGS | ROOM_NOTIFY_DM);
  1498. metadata.AddInt32("room_disallowed_flags", 0 | ROOM_AUTOCREATE);
  1499. _SendMessage(&metadata);
  1500. }
  1501. void
  1502. JabberHandler::handleMUCItems(gloox::MUCRoom *room, const gloox::Disco::ItemList &items)
  1503. {
  1504. BString chat_id = _MUCChatId(room);
  1505. BStringList nicks;
  1506. BStringList ids;
  1507. if (chat_id.IsEmpty() == true)
  1508. return;
  1509. for (auto item: items) {
  1510. BString nick = item->jid().resource().c_str();
  1511. nicks.Add(nick);
  1512. // Unless it's the user, derive ID from room resource
  1513. if (fNick != nick) {
  1514. BString user_id(chat_id);
  1515. user_id << "/" << nick;
  1516. ids.Add(user_id);
  1517. }
  1518. else
  1519. ids.Add(BString(fJid.bare().c_str()));
  1520. }
  1521. BMessage msg(IM_MESSAGE);
  1522. msg.AddStrings("user_id", ids);
  1523. msg.AddStrings("user_name", nicks);
  1524. msg.AddString("chat_id", chat_id);
  1525. msg.AddInt32("im_what", IM_ROOM_PARTICIPANTS);
  1526. _SendMessage(&msg);
  1527. }
  1528. void
  1529. JabberHandler::handleMUCConfigList(gloox::MUCRoom* room, const gloox::MUCListItemList &items,
  1530. gloox::MUCOperation operation)
  1531. {
  1532. }
  1533. void
  1534. JabberHandler::handleMUCConfigForm(gloox::MUCRoom* room, const gloox::DataForm &form)
  1535. {
  1536. }
  1537. void
  1538. JabberHandler::handleMUCConfigResult(gloox::MUCRoom* room, bool success,
  1539. gloox::MUCOperation operation)
  1540. {
  1541. }
  1542. void
  1543. JabberHandler::handleMUCRequest(gloox::MUCRoom* room, const gloox::DataForm &form)
  1544. {
  1545. }
  1546. void
  1547. JabberHandler::handleItemAdded(const gloox::JID&)
  1548. {
  1549. }
  1550. void
  1551. JabberHandler::handleItemSubscribed(const gloox::JID&)
  1552. {
  1553. }
  1554. void
  1555. JabberHandler::handleItemUnsubscribed(const gloox::JID&)
  1556. {
  1557. }
  1558. void
  1559. JabberHandler::handleItemRemoved(const gloox::JID&)
  1560. {
  1561. }
  1562. void
  1563. JabberHandler::handleItemUpdated(const gloox::JID&)
  1564. {
  1565. }
  1566. void
  1567. JabberHandler::handleRosterPresence(const gloox::RosterItem& item,
  1568. const std::string& resource,
  1569. gloox::Presence::PresenceType type,
  1570. const std::string& presenceMsg)
  1571. {
  1572. _StatusSetMsg(item.jidJID().full().c_str(), type, presenceMsg.c_str(),
  1573. resource.c_str());
  1574. }
  1575. void
  1576. JabberHandler::handleSelfPresence(const gloox::RosterItem& item, const std::string&,
  1577. gloox::Presence::PresenceType type,
  1578. const std::string& presenceMsg)
  1579. {
  1580. BMessage msg(IM_MESSAGE);
  1581. msg.AddInt32("im_what", IM_OWN_CONTACT_INFO);
  1582. msg.AddString("protocol", Signature());
  1583. msg.AddString("user_id", item.jidJID().full().c_str());
  1584. msg.AddString("user_name", fNick.String());
  1585. msg.AddInt32("subscription", item.subscription());
  1586. msg.AddInt32("status", _GlooxStatusToApp(type));
  1587. msg.AddString("message", presenceMsg.c_str());
  1588. // Groups
  1589. gloox::StringList g = item.groups();
  1590. gloox::StringList::const_iterator it_g = g.begin();
  1591. for (; it_g != g.end(); ++it_g)
  1592. msg.AddString("group", (*it_g).c_str());
  1593. // Resources
  1594. gloox::RosterItem::ResourceMap::const_iterator rit
  1595. = item.resources().begin();
  1596. for (; rit != item.resources().end(); ++rit)
  1597. msg.AddString("resource", (*rit).first.c_str());
  1598. _SendMessage(&msg);
  1599. }
  1600. bool
  1601. JabberHandler::handleSubscriptionRequest(const gloox::JID&, const std::string&)
  1602. {
  1603. return true;
  1604. }
  1605. bool
  1606. JabberHandler::handleUnsubscriptionRequest(const gloox::JID&, const std::string&)
  1607. {
  1608. return true;
  1609. }
  1610. void
  1611. JabberHandler::handleNonrosterPresence(const gloox::Presence&)
  1612. {
  1613. }
  1614. void
  1615. JabberHandler::handleRosterError(const gloox::IQ&)
  1616. {
  1617. }
  1618. void
  1619. JabberHandler::handleLog(gloox::LogLevel level, gloox::LogArea,
  1620. const std::string& msg)
  1621. {
  1622. if (level >= gloox::LogLevelWarning)
  1623. std::cout << msg << std::endl;
  1624. }
  1625. void
  1626. JabberHandler::handleVCard(const gloox::JID& jid, const gloox::VCard* card)
  1627. {
  1628. if (!card)
  1629. return;
  1630. // Throttles updates to your own VCard― ime some servers spam for no reason
  1631. if (jid.bare() == fJid.bare()) {
  1632. bigtime_t last = fLastOwnVCard;
  1633. fLastOwnVCard = time(NULL);
  1634. if (fLastOwnVCard - last < 60)
  1635. return;
  1636. }
  1637. gloox::VCard::Name name = card->name();
  1638. gloox::VCard::Photo photo = card->photo();
  1639. BString nick(card->nickname().c_str());
  1640. gloox::RosterItem* item = fClient->rosterManager()->getRosterItem(jid);
  1641. if (item != NULL)
  1642. nick = item->name().c_str();
  1643. std::string fullName = name.family + " " + name.given;
  1644. BMessage msg(IM_MESSAGE);
  1645. msg.AddInt32("im_what", IM_EXTENDED_CONTACT_INFO);
  1646. msg.AddString("user_id", jid.bare().c_str());
  1647. msg.AddString("user_name", nick);
  1648. msg.AddString("family_name", name.family.c_str());
  1649. msg.AddString("given_name", name.given.c_str());
  1650. msg.AddString("middle_name", name.middle.c_str());
  1651. msg.AddString("prefix", name.prefix.c_str());
  1652. msg.AddString("suffix", name.suffix.c_str());
  1653. msg.AddString("full_name", fullName.c_str());
  1654. _SendMessage(&msg);
  1655. // Return if there's no avatar icon
  1656. if (!photo.binval.c_str())
  1657. return;
  1658. if (_SetupAvatarCache() == B_OK)
  1659. // Cache avatar icon and notify the change
  1660. _CacheAvatar(jid.bare().c_str(), photo.binval.c_str(),
  1661. photo.binval.length());
  1662. }
  1663. void
  1664. JabberHandler::handleVCardResult(gloox::VCardHandler::VCardContext context,
  1665. const gloox::JID& jid,
  1666. gloox::StanzaError)
  1667. {
  1668. //if (context == gloox::VCardHandler::FetchVCard)
  1669. //else
  1670. }
  1671. OurClient::OurClient(const gloox::JID jid, const char* password)
  1672. :
  1673. gloox::Client(jid, password)
  1674. {
  1675. }
  1676. void
  1677. OurClient::handleTag(gloox::Tag* tag)
  1678. {
  1679. if (DEBUG_ENABLED)
  1680. std::cerr << "Tag\t" << tag->xml() << std::endl;
  1681. gloox::Client::handleTag(tag);
  1682. }
  1683. InviteHandler::InviteHandler(gloox::ClientBase* client, JabberHandler* handler)
  1684. :
  1685. gloox::MUCInvitationHandler(client),
  1686. fHandler(handler)
  1687. {
  1688. }
  1689. void
  1690. InviteHandler::handleMUCInvitation(const gloox::JID& room, const gloox::JID& from,
  1691. const std::string& reason, const std::string& body,
  1692. const std::string& password, bool cont,
  1693. const std::string& thread)
  1694. {
  1695. std::string chat_name = room.resource().c_str();
  1696. BString chat_id = room.full().c_str();
  1697. if (chat_name.empty() == true)
  1698. chat_name = chat_id.String();
  1699. if (password.empty() == false)
  1700. chat_id << "#" << password.c_str();
  1701. BMessage invite(IM_MESSAGE);
  1702. invite.AddInt32("im_what", IM_ROOM_INVITE_RECEIVED);
  1703. invite.AddString("chat_id", chat_id);
  1704. invite.AddString("chat_name", chat_name.c_str());
  1705. invite.AddString("user_id", from.bare().c_str());
  1706. if (reason.empty() == false)
  1707. invite.AddString("body", reason.c_str());
  1708. invite.AddString("protocol", fHandler->Signature());
  1709. fHandler->MessengerInterface()->SendMessage(new BMessage(invite));
  1710. }