IrcProtocol.cpp 33 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420
  1. /*
  2. * Copyright 2021, Jaidyn Levesque <jadedctrl@teknik.io>
  3. * Copyright 2017, Akshay Agarwal <agarwal.akshay.akshay8@gmail.com>
  4. * All rights reserved. Distributed under the terms of the MIT license.
  5. */
  6. #include "IrcProtocol.h"
  7. #include <iostream>
  8. #include <Catalog.h>
  9. #include <Directory.h>
  10. #include <FindDirectory.h>
  11. #include <Font.h>
  12. #include <Resources.h>
  13. #include <SecureSocket.h>
  14. #include <Socket.h>
  15. #include <libinterface/BitmapUtils.h>
  16. #include <AppConstants.h>
  17. #include <ChatOMatic.h>
  18. #include <ChatProtocolMessages.h>
  19. #include <Flags.h>
  20. #include <Utils.h>
  21. #undef B_TRANSLATION_CONTEXT
  22. #define B_TRANSLATION_CONTEXT "IrcProtocol"
  23. const int32 IRC_CMD = 'ICmd';
  24. status_t
  25. connect_thread(void* data)
  26. {
  27. IrcProtocol* protocol = (IrcProtocol*)data;
  28. protocol->Connect();
  29. status_t status = protocol->Loop();
  30. exit(status);
  31. }
  32. IrcProtocol::IrcProtocol()
  33. :
  34. fSocket(NULL),
  35. fNick(NULL),
  36. fIdent(NULL),
  37. fReady(false),
  38. fWriteLocked(false)
  39. {
  40. }
  41. IrcProtocol::~IrcProtocol()
  42. {
  43. Shutdown();
  44. }
  45. status_t
  46. IrcProtocol::Init(ChatProtocolMessengerInterface* interface)
  47. {
  48. fMessenger = interface;
  49. return B_OK;
  50. }
  51. status_t
  52. IrcProtocol::Shutdown()
  53. {
  54. _SaveContacts();
  55. BString cmd = "QUIT :";
  56. cmd << fPartText;
  57. _SendIrc(cmd);
  58. kill_thread(fRecvThread);
  59. return B_OK;
  60. }
  61. status_t
  62. IrcProtocol::UpdateSettings(BMessage* settings)
  63. {
  64. fNick = settings->FindString("nick");
  65. fPartText = settings->GetString("part", "Chat-O-Matic[0.1]: i've been liquified!");
  66. fUser = settings->FindString("ident");
  67. fRealName = settings->FindString("real_name");
  68. fServer = settings->FindString("server");
  69. fPassword = settings->FindString("password");
  70. fPort = settings->FindInt32("port");
  71. fSsl = settings->GetBool("ssl", false);
  72. fRecvThread = spawn_thread(connect_thread, "what_a_tangled_web_we_weave",
  73. B_NORMAL_PRIORITY, (void*)this);
  74. if (fRecvThread < B_OK)
  75. return B_ERROR;
  76. return B_OK;
  77. }
  78. status_t
  79. IrcProtocol::Process(BMessage* msg)
  80. {
  81. int32 im_what = msg->FindInt32("im_what");
  82. switch (im_what) {
  83. case IRC_CMD:
  84. {
  85. BStringList words;
  86. BString line = msg->GetString("misc_str", "");
  87. line.Split(" ", true, words);
  88. BString command = words.First();
  89. if (command.ICompare("WHOIS") == 0)
  90. fWhoIsRequested = true;
  91. else if (command.ICompare("WHO") == 0)
  92. fWhoRequested = true;
  93. _SendIrc(line);
  94. break;
  95. }
  96. case IM_SET_OWN_STATUS:
  97. {
  98. int32 status = msg->FindInt32("status");
  99. BString status_msg = msg->FindString("message");
  100. BMessage statusSet(IM_MESSAGE);
  101. statusSet.AddInt32("im_what", IM_OWN_STATUS_SET);
  102. switch (status) {
  103. case STATUS_ONLINE:
  104. statusSet.AddInt32("status", STATUS_ONLINE);
  105. resume_thread(fRecvThread);
  106. break;
  107. case STATUS_OFFLINE:
  108. statusSet.AddInt32("status", STATUS_OFFLINE);
  109. Shutdown();
  110. break;
  111. default:
  112. break;
  113. }
  114. if (status == STATUS_ONLINE || status == STATUS_OFFLINE)
  115. _SendMsg(&statusSet);
  116. break;
  117. }
  118. case IM_SEND_MESSAGE:
  119. {
  120. BString chat_id = msg->FindString("chat_id");
  121. BString body = msg->FindString("body");
  122. if (chat_id.IsEmpty() == false || body.IsEmpty() == false) {
  123. BStringList lines;
  124. body.Split("\n", true, lines);
  125. for (int i = 0; i < lines.CountStrings(); i++) {
  126. BString cmd = "PRIVMSG ";
  127. cmd << chat_id << " :" << lines.StringAt(i);
  128. _SendIrc(cmd);
  129. BMessage sent(IM_MESSAGE);
  130. sent.AddInt32("im_what", IM_MESSAGE_SENT);
  131. sent.AddString("user_id", fIdent);
  132. sent.AddString("chat_id", chat_id);
  133. sent.AddString("body", lines.StringAt(i));
  134. _SendMsg(&sent);
  135. }
  136. }
  137. break;
  138. }
  139. case IM_CREATE_CHAT:
  140. {
  141. BString user_id;
  142. if (msg->FindString("user_id", &user_id) != B_OK)
  143. break;
  144. BString user_name = _IdentNick(user_id);
  145. if (user_name != user_id) {
  146. BMessage created(IM_MESSAGE);
  147. created.AddInt32("im_what", IM_CHAT_CREATED);
  148. created.AddString("chat_id", user_name);
  149. created.AddString("user_id", user_id);
  150. _SendMsg(&created);
  151. fChannels.Add(user_name);
  152. break;
  153. }
  154. // If it's not a known user, we need to get their ID/nick somehow
  155. // … that is, through the WHO.
  156. fWhoIm = user_id;
  157. BString cmd("WHOIS ");
  158. cmd << user_id << "\n";
  159. _SendIrc(cmd);
  160. break;
  161. }
  162. case IM_JOIN_ROOM:
  163. case IM_CREATE_ROOM:
  164. case IM_ROOM_INVITE_ACCEPT:
  165. {
  166. BString chat_id;
  167. if (msg->FindString("chat_id", &chat_id) == B_OK) {
  168. BString cmd = "JOIN ";
  169. cmd << chat_id;
  170. _SendIrc(cmd);
  171. }
  172. break;
  173. }
  174. case IM_LEAVE_ROOM:
  175. {
  176. BString chat_id;
  177. if (msg->FindString("chat_id", &chat_id) == B_OK) {
  178. if (_IsChannelName(chat_id) == true) {
  179. BString cmd = "PART ";
  180. cmd << chat_id << " * :" << fPartText;
  181. _SendIrc(cmd);
  182. }
  183. else {
  184. BMessage left(IM_MESSAGE);
  185. left.AddInt32("im_what", IM_ROOM_LEFT);
  186. left.AddString("chat_id", chat_id);
  187. _SendMsg(&left);
  188. fChannels.Remove(chat_id);
  189. }
  190. }
  191. break;
  192. }
  193. case IM_GET_ROOM_METADATA:
  194. {
  195. BString chat_id;
  196. if (msg->FindString("chat_id", &chat_id) == B_OK) {
  197. BMessage meta(IM_MESSAGE);
  198. meta.AddInt32("im_what", IM_ROOM_METADATA);
  199. meta.AddString("chat_id", chat_id);
  200. meta.AddInt32("room_default_flags",
  201. ROOM_LOG_LOCALLY | ROOM_POPULATE_LOGS | ROOM_NOTIFY_DM);
  202. if (_IsChannelName(chat_id) == false)
  203. meta.AddInt32("room_disallowed_flags", ROOM_AUTOJOIN);
  204. _SendMsg(&meta);
  205. }
  206. break;
  207. }
  208. case IM_GET_ROOM_PARTICIPANTS:
  209. {
  210. BString chat_id;
  211. if (msg->FindString("chat_id", &chat_id) != B_OK)
  212. break;
  213. // Rooms are populated with RPL_WHOREPLY, chats RPL_WHOISUSER
  214. BString cmd;
  215. if (_IsChannelName(chat_id) == true)
  216. cmd = "WHO ";
  217. else
  218. cmd = "WHOIS ";
  219. cmd << chat_id << "\n";
  220. _SendIrc(cmd);
  221. break;
  222. }
  223. case IM_ROOM_BAN_PARTICIPANT:
  224. case IM_ROOM_KICK_PARTICIPANT:
  225. {
  226. BString chat_id = msg->FindString("chat_id");
  227. BString user_id = msg->FindString("user_id");
  228. BString body;
  229. if (chat_id.IsEmpty() == true || user_id.IsEmpty() == true)
  230. break;
  231. if (im_what == IM_ROOM_BAN_PARTICIPANT) {
  232. BString cmd("MODE ");
  233. cmd << chat_id << " +b " << _IdentNick(user_id) << "!*@*";
  234. _SendIrc(cmd);
  235. }
  236. if (msg->FindString("body", &body) != B_OK
  237. && im_what == IM_ROOM_BAN_PARTICIPANT)
  238. body = B_TRANSLATE("You've been banned, nerd");
  239. else if (body.IsEmpty() == true)
  240. body = B_TRANSLATE("Watch the door on your way out");
  241. BString cmd("KICK ");
  242. cmd << chat_id << " " << _IdentNick(user_id);
  243. cmd << " :" << body;
  244. _SendIrc(cmd);
  245. break;
  246. }
  247. case IM_ROOM_UNBAN_PARTICIPANT:
  248. {
  249. BString chat_id = msg->FindString("chat_id");
  250. BString user_id = msg->FindString("user_id");
  251. if (chat_id.IsEmpty() == false && user_id.IsEmpty() == false) {
  252. BString cmd("MODE ");
  253. cmd << chat_id << " -b " << _IdentNick(user_id) << "!*@*";
  254. _SendIrc(cmd);
  255. }
  256. break;
  257. }
  258. case IM_ROOM_SEND_INVITE:
  259. {
  260. BString chat_id = msg->FindString("chat_id");
  261. BString user_id = msg->FindString("user_id");
  262. if (chat_id.IsEmpty() == false && user_id.IsEmpty() == false) {
  263. BString cmd("INVITE ");
  264. cmd << _IdentNick(user_id) << " " << chat_id;
  265. _SendIrc(cmd);
  266. }
  267. break;
  268. }
  269. case IM_SET_OWN_NICKNAME:
  270. {
  271. BString user_name;
  272. if (msg->FindString("user_name", &user_name) == B_OK) {
  273. BString cmd("NICK ");
  274. cmd << user_name;
  275. _SendIrc(cmd);
  276. }
  277. break;
  278. }
  279. case IM_ROSTER_ADD_CONTACT:
  280. {
  281. BString user_nick;
  282. if (msg->FindString("user_id", &user_nick) == B_OK)
  283. _AddContact(user_nick);
  284. break;
  285. }
  286. case IM_ROSTER_REMOVE_CONTACT:
  287. {
  288. BString user_id;
  289. if (msg->FindString("user_id", &user_id) == B_OK)
  290. _RemoveContact(_NickIdent(user_id));
  291. break;
  292. }
  293. case IM_GET_CONTACT_INFO:
  294. case IM_GET_EXTENDED_CONTACT_INFO:
  295. {
  296. BString user_id;
  297. if (msg->FindString("user_id", &user_id) != B_OK)
  298. break;
  299. BMessage info(IM_MESSAGE);
  300. if (im_what == IM_GET_CONTACT_INFO)
  301. info.AddInt32("im_what", IM_CONTACT_INFO);
  302. else
  303. info.AddInt32("im_what", IM_EXTENDED_CONTACT_INFO);
  304. info.AddString("user_id", user_id);
  305. info.AddString("user_name", _IdentNick(user_id));
  306. if (fOfflineContacts.HasString(_IdentNick(user_id)) == true)
  307. info.AddInt32("status", (int32)STATUS_OFFLINE);
  308. else
  309. info.AddInt32("status", (int32)STATUS_ONLINE);
  310. _SendMsg(&info);
  311. break;
  312. }
  313. case IM_SET_ROOM_SUBJECT:
  314. {
  315. BString chat_id;
  316. BString body = msg->FindString("subject");
  317. if (msg->FindString("chat_id", &chat_id) == B_OK) {
  318. BString cmd("TOPIC ");
  319. cmd << chat_id << " :" << body;
  320. _SendIrc(cmd);
  321. }
  322. break;
  323. }
  324. default:
  325. std::cout << "Unhandled message for IRC:\n";
  326. msg->PrintToStream();
  327. return B_ERROR;
  328. }
  329. return B_OK;
  330. }
  331. BMessage
  332. IrcProtocol::SettingsTemplate(const char* name)
  333. {
  334. BMessage settings;
  335. if (strcmp(name, "account") == 0)
  336. settings = _AccountTemplate();
  337. else if (strcmp(name, "join_room") == 0 || strcmp(name, "create_room") == 0)
  338. settings = _RoomTemplate();
  339. else if (strcmp(name, "roster") == 0)
  340. settings = _RosterTemplate();
  341. return settings;
  342. }
  343. BObjectList<BMessage>
  344. IrcProtocol::Commands()
  345. {
  346. BMessage handle(IM_MESSAGE);
  347. handle.AddInt32("im_what", IRC_CMD);
  348. handle.AddString("cmd_name", "/");
  349. BMessage* cmd = new BMessage();
  350. cmd->AddString("_name", "/");
  351. cmd->AddString("_desc", B_TRANSLATE("Send a raw IRC command to the server. E.g., '// HELP' or '// WHOIS'."));
  352. cmd->AddBool("_proto", true);
  353. cmd->AddMessage("_msg", &handle);
  354. cmd->AddString("class", "ChatCommand");
  355. BObjectList<BMessage> cmds;
  356. cmds.AddItem(cmd);
  357. return cmds;
  358. }
  359. BBitmap*
  360. IrcProtocol::Icon() const
  361. {
  362. return ReadNodeIcon(fAddOnPath.Path(), B_LARGE_ICON, true);
  363. }
  364. status_t
  365. IrcProtocol::Connect()
  366. {
  367. fSocket = fSsl ? new BSecureSocket : new BSocket;
  368. if (fSocket->Connect(BNetworkAddress(fServer, fPort)) != B_OK)
  369. return B_ERROR;
  370. if (fPassword.IsEmpty() == false) {
  371. BString passMsg = "PASS ";
  372. passMsg << fPassword;
  373. _SendIrc(passMsg);
  374. }
  375. BString userMsg = "USER ";
  376. userMsg << fUser << " * 0 :" << fRealName;
  377. _SendIrc(userMsg);
  378. BString nickMsg = "NICK ";
  379. nickMsg << fNick;
  380. _SendIrc(nickMsg);
  381. return B_OK;
  382. }
  383. status_t
  384. IrcProtocol::Loop()
  385. {
  386. fWhoIsRequested = false;
  387. fWhoRequested = false;
  388. while (fSocket != NULL && fSocket->IsConnected() == true)
  389. _ProcessLine(_ReadUntilNewline(fSocket, &fRemainingBuf));
  390. return B_OK;
  391. }
  392. void
  393. IrcProtocol::_ProcessLine(BString line)
  394. {
  395. BStringList words;
  396. line.RemoveCharsSet("\n\r");
  397. line.Split(" ", true, words);
  398. BString sender = _LineSender(words);
  399. BString code = _LineCode(words);
  400. BStringList params = _LineParameters(words, line);
  401. int32 numeric;
  402. if ((numeric = atoi(code.String())) > 0)
  403. _ProcessNumeric(numeric, sender, params, line);
  404. else
  405. _ProcessCommand(code, sender, params, line);
  406. }
  407. void
  408. IrcProtocol::_ProcessNumeric(int32 numeric, BString sender, BStringList params,
  409. BString line)
  410. {
  411. if (numeric > 400) {
  412. _ProcessNumericError(numeric, sender, params, line);
  413. return;
  414. }
  415. // Act on the numeric as appropriate
  416. switch (numeric) {
  417. case RPL_WELCOME:
  418. {
  419. if (params.CountStrings() == 2)
  420. fNick = params.First();
  421. BString cmd("WHOIS ");
  422. cmd << fNick << "\n";
  423. _SendIrc(cmd);
  424. break;
  425. }
  426. case RPL_WHOISUSER:
  427. {
  428. BString nick = params.StringAt(1);
  429. BString user = params.StringAt(2);
  430. BString host = params.StringAt(3);
  431. BString ident = user;
  432. ident << "@" << host;
  433. fIdentNicks.RemoveItemFor(ident);
  434. fIdentNicks.AddItem(ident, nick);
  435. // If is a contact, let's go!
  436. _UpdateContact(nick, ident, true);
  437. // Contains the own user's contact info― protocol ready!
  438. if (fReady == false && nick == fNick) {
  439. fUser = user.String();
  440. _MakeReady(nick, ident);
  441. }
  442. // Used in the creation of a one-on-one chat
  443. else if (fWhoIm == user || fWhoIm == nick) {
  444. fWhoIm = "";
  445. BMessage created(IM_MESSAGE);
  446. created.AddInt32("im_what", IM_CHAT_CREATED);
  447. created.AddString("chat_id", nick);
  448. created.AddString("user_id", ident);
  449. _SendMsg(&created);
  450. fChannels.Add(nick);
  451. }
  452. // Used to populate a one-on-one chat's userlist… lol, I know.
  453. else if (fWhoIsRequested == false && fChannels.HasString(nick)) {
  454. BMessage user(IM_MESSAGE);
  455. user.AddInt32("im_what", IM_ROOM_PARTICIPANTS);
  456. user.AddString("chat_id", nick);
  457. user.AddString("user_id", ident);
  458. user.AddString("user_name", nick);
  459. _SendMsg(&user);
  460. }
  461. break;
  462. }
  463. case RPL_WHOREPLY:
  464. {
  465. BString channel = params.StringAt(1);
  466. BString user = params.StringAt(2);
  467. BString host = params.StringAt(3);
  468. BString nick = params.StringAt(5);
  469. BString role = params.StringAt(6);
  470. BString ident = user;
  471. ident << "@" << host;
  472. fIdentNicks.RemoveItemFor(ident);
  473. fIdentNicks.AddItem(ident, nick);
  474. // Used to populate a room's userlist (one-by-one… :p)
  475. if (fWhoRequested == false && _IsChannelName(channel)) {
  476. // Send the participant themself
  477. BMessage user(IM_MESSAGE);
  478. user.AddInt32("im_what", IM_ROOM_PARTICIPANTS);
  479. user.AddString("chat_id", channel);
  480. user.AddString("user_id", ident);
  481. user.AddString("user_name", nick);
  482. _SendMsg(&user);
  483. // Now let's crunch the appropriate role…
  484. bool away = false;
  485. UserRole priority = ROOM_MEMBER;
  486. for (int i=0; i < role.CountBytes(0, role.CountChars()); i++) {
  487. char c = role.ByteAt(i);
  488. switch (c) {
  489. case 'G':
  490. case 'H':
  491. away = false;
  492. break;
  493. case 'A':
  494. away = true;
  495. break;
  496. case '%':
  497. priority = ROOM_HALFOP;
  498. break;
  499. case '@':
  500. priority = ROOM_OPERATOR;
  501. break;
  502. case '*':
  503. priority = IRC_OPERATOR;
  504. break;
  505. }
  506. }
  507. // And send the user's role
  508. BMessage sensei(IM_MESSAGE);
  509. sensei.AddInt32("im_what", IM_ROOM_ROLECHANGED);
  510. sensei.AddString("chat_id", channel);
  511. sensei.AddString("user_id", ident);
  512. sensei.AddInt32("role_priority", priority);
  513. sensei.AddString("role_title", _RoleTitle(priority));
  514. sensei.AddInt32("role_perms", _RolePerms(priority));
  515. _SendMsg(&sensei);
  516. // Also status! Can't forget that
  517. BMessage status(IM_MESSAGE);
  518. status.AddInt32("im_what", IM_USER_STATUS_SET);
  519. status.AddString("user_id", ident);
  520. if (away == true)
  521. status.AddInt32("status", STATUS_AWAY);
  522. else
  523. status.AddInt32("status", STATUS_ONLINE);
  524. _SendMsg(&status);
  525. }
  526. break;
  527. }
  528. case RPL_TOPIC:
  529. {
  530. BString chat_id = params.StringAt(1);
  531. BString subject = params.Last();
  532. BMessage topic(IM_MESSAGE);
  533. topic.AddInt32("im_what", IM_ROOM_SUBJECT_SET);
  534. topic.AddString("subject", subject);
  535. topic.AddString("chat_id", chat_id);
  536. _SendMsg(&topic);
  537. break;
  538. }
  539. }
  540. // Now, to determine if the line should be sent to system buffer
  541. switch (numeric) {
  542. case RPL_ENDOFWHO:
  543. fWhoRequested = false;
  544. break;
  545. case RPL_ENDOFWHOIS:
  546. fWhoIsRequested = false;
  547. break;
  548. case RPL_MOTDSTART:
  549. case RPL_MOTD:
  550. case RPL_ENDOFMOTD:
  551. {
  552. BString body = params.Last();
  553. if (numeric == RPL_MOTDSTART)
  554. body = "――MOTD start――";
  555. else if (numeric == RPL_ENDOFMOTD)
  556. body = "――MOTD end――";
  557. BMessage send(IM_MESSAGE);
  558. send.AddInt32("im_what", IM_MESSAGE_RECEIVED);
  559. send.AddString("body", body);
  560. _SendMsg(&send);
  561. break;
  562. }
  563. case RPL_WHOREPLY:
  564. if (fWhoRequested == false)
  565. break;
  566. case RPL_WHOISUSER:
  567. if (fWhoIsRequested == false)
  568. break;
  569. default:
  570. BMessage send(IM_MESSAGE);
  571. send.AddInt32("im_what", IM_MESSAGE_RECEIVED);
  572. send.AddString("body", line);
  573. _SendMsg(&send);
  574. }
  575. }
  576. void
  577. IrcProtocol::_ProcessNumericError(int32 numeric, BString sender,
  578. BStringList params, BString line)
  579. {
  580. switch (numeric) {
  581. case ERR_NICKNAMEINUSE:
  582. {
  583. fNick << "_";
  584. BString cmd("NICK ");
  585. cmd << fNick << "\n";
  586. _SendIrc(cmd);
  587. break;
  588. }
  589. default:
  590. {
  591. BMessage err(IM_MESSAGE);
  592. err.AddInt32("im_what", IM_MESSAGE_RECEIVED);
  593. err.AddString("body", line);
  594. _SendMsg(&err);
  595. }
  596. }
  597. }
  598. void
  599. IrcProtocol::_ProcessCommand(BString command, BString sender,
  600. BStringList params, BString line)
  601. {
  602. // If protocol uninitialized and the user's ident is mentioned― use it!
  603. if (fReady == false && _SenderNick(sender) == fNick)
  604. _MakeReady(_SenderNick(sender), _SenderIdent(sender));
  605. if (sender == "PING")
  606. {
  607. BString cmd = "PONG ";
  608. cmd << params.Last() << "\n";
  609. _SendIrc(cmd);
  610. }
  611. else if (command == "PRIVMSG")
  612. {
  613. BString chat_id = params.First();
  614. BString user_id = _SenderIdent(sender);
  615. BString user_name = _SenderNick(sender);
  616. BString body = params.Last();
  617. if (_IsChannelName(chat_id) == false)
  618. chat_id = _SenderNick(sender);
  619. if (fChannels.HasString(chat_id) == false)
  620. fChannels.Add(chat_id);
  621. _UpdateContact(user_name, user_id, true);
  622. BMessage chat(IM_MESSAGE);
  623. chat.AddInt32("im_what", IM_MESSAGE_RECEIVED);
  624. chat.AddString("chat_id", chat_id);
  625. chat.AddString("user_id", user_id);
  626. chat.AddString("user_name", user_name);
  627. _AddFormatted(&chat, "body", body);
  628. _SendMsg(&chat);
  629. }
  630. else if (command == "NOTICE")
  631. {
  632. BString chat_id = params.First();
  633. BMessage send(IM_MESSAGE);
  634. send.AddInt32("im_what", IM_MESSAGE_RECEIVED);
  635. if (_IsChannelName(chat_id) == false)
  636. chat_id = _SenderNick(sender);
  637. if (fChannels.HasString(chat_id) == false)
  638. fChannels.Add(chat_id);
  639. if (chat_id != "AUTH" || chat_id != "*")
  640. send.AddString("chat_id", chat_id);
  641. if (sender.IsEmpty() == false) {
  642. send.AddString("user_id", _SenderIdent(sender));
  643. send.AddString("user_name", _SenderNick(sender));
  644. }
  645. send.AddString("body", params.Last());
  646. _SendMsg(&send);
  647. }
  648. else if (command == "TOPIC")
  649. {
  650. BString chat_id = params.First();
  651. BString subject = params.Last();
  652. BMessage topic(IM_MESSAGE);
  653. topic.AddInt32("im_what", IM_ROOM_SUBJECT_SET);
  654. topic.AddString("subject", subject);
  655. topic.AddString("chat_id", chat_id);
  656. _SendMsg(&topic);
  657. }
  658. else if (command == "JOIN")
  659. {
  660. BString chat_id = params.First();
  661. BString user_id = _SenderIdent(sender);
  662. BString user_name = _SenderNick(sender);
  663. _UpdateContact(user_name, user_id, true);
  664. BMessage joined(IM_MESSAGE);
  665. joined.AddString("chat_id", chat_id);
  666. if (_SenderIdent(sender) == fIdent) {
  667. joined.AddInt32("im_what", IM_ROOM_JOINED);
  668. fChannels.Add(chat_id);
  669. }
  670. else {
  671. joined.AddInt32("im_what", IM_ROOM_PARTICIPANT_JOINED);
  672. joined.AddString("user_id", user_id);
  673. joined.AddString("user_name", user_name);
  674. fIdentNicks.AddItem(user_id, user_name);
  675. }
  676. _SendMsg(&joined);
  677. BMessage status(IM_MESSAGE);
  678. status.AddInt32("im_what", IM_USER_STATUS_SET);
  679. status.AddString("user_id", user_id);
  680. status.AddInt32("status", STATUS_ONLINE);
  681. _SendMsg(&status);
  682. }
  683. else if (command == "PART")
  684. {
  685. BString chat_id = params.First();
  686. BString body = B_TRANSLATE("left: ");
  687. body << params.Last();
  688. BMessage left(IM_MESSAGE);
  689. left.AddString("chat_id", chat_id);
  690. left.AddString("body", body);
  691. if (_SenderIdent(sender) == fIdent) {
  692. left.AddInt32("im_what", IM_ROOM_LEFT);
  693. fChannels.Remove(chat_id);
  694. }
  695. else {
  696. left.AddInt32("im_what", IM_ROOM_PARTICIPANT_LEFT);
  697. left.AddString("user_id", _SenderIdent(sender));
  698. left.AddString("user_name", _SenderNick(sender));
  699. }
  700. _SendMsg(&left);
  701. }
  702. else if (command == "KICK")
  703. {
  704. BString chat_id = params.First();
  705. BString user_id = params.StringAt(1);
  706. BMessage foot(IM_MESSAGE);
  707. foot.AddInt32("im_what", IM_ROOM_PARTICIPANT_KICKED);
  708. foot.AddString("chat_id", chat_id);
  709. foot.AddString("user_name", _IdentNick(user_id));
  710. foot.AddString("user_id", _NickIdent(user_id));
  711. if (params.CountStrings() == 3)
  712. foot.AddString("body", params.StringAt(2));
  713. _SendMsg(&foot);
  714. }
  715. else if (command == "QUIT")
  716. {
  717. BString user_id = _SenderIdent(sender);
  718. BString user_name = _SenderNick(sender);
  719. _UpdateContact(user_name, user_id, false);
  720. BString body = B_TRANSLATE("quit: ");
  721. body << params.Last();
  722. for (int i = 0; i < fChannels.CountStrings(); i++) {
  723. if (_IsChannelName(fChannels.StringAt(i)) == false)
  724. continue;
  725. BMessage left(IM_MESSAGE);
  726. left.AddInt32("im_what", IM_ROOM_PARTICIPANT_LEFT);
  727. left.AddString("user_id", user_id);
  728. left.AddString("user_name", user_name);
  729. left.AddString("chat_id", fChannels.StringAt(i));
  730. _SendMsg(&left);
  731. }
  732. BMessage status(IM_MESSAGE);
  733. status.AddInt32("im_what", IM_USER_STATUS_SET);
  734. status.AddString("user_id", user_id);
  735. status.AddInt32("status", STATUS_OFFLINE);
  736. _SendMsg(&status);
  737. }
  738. else if (command == "INVITE")
  739. {
  740. BMessage invite(IM_MESSAGE);
  741. invite.AddInt32("im_what", IM_ROOM_INVITE_RECEIVED);
  742. invite.AddString("chat_id", params.Last());
  743. invite.AddString("user_id", _SenderIdent(sender));
  744. _SendMsg(&invite);
  745. }
  746. else if (command == "NICK")
  747. {
  748. BString ident = _SenderIdent(sender);
  749. BString user_name = params.Last();
  750. BMessage nick(IM_MESSAGE);
  751. nick.AddString("user_name", user_name);
  752. if (ident == fIdent) {
  753. nick.AddInt32("im_what", IM_OWN_NICKNAME_SET);
  754. fNick = user_name;
  755. }
  756. else {
  757. nick.AddInt32("im_what", IM_USER_NICKNAME_SET);
  758. nick.AddString("user_id", ident);
  759. _RenameContact(ident, user_name);
  760. fIdentNicks.RemoveItemFor(ident);
  761. fIdentNicks.AddItem(ident, user_name);
  762. }
  763. _SendMsg(&nick);
  764. }
  765. }
  766. void
  767. IrcProtocol::_MakeReady(BString nick, BString ident)
  768. {
  769. fNick = nick;
  770. fIdent = ident;
  771. fReady = true;
  772. BMessage ready(IM_MESSAGE);
  773. ready.AddInt32("im_what", IM_PROTOCOL_READY);
  774. _SendMsg(&ready);
  775. BMessage self(IM_MESSAGE);
  776. self.AddInt32("im_what", IM_OWN_CONTACT_INFO);
  777. self.AddString("user_id", fIdent);
  778. self.AddString("user_name", fNick);
  779. _SendMsg(&self);
  780. _SendIrc("MOTD\n");
  781. _LoadContacts();
  782. _JoinDefaultRooms();
  783. }
  784. BString
  785. IrcProtocol::_LineSender(BStringList words)
  786. {
  787. BString sender;
  788. if (words.CountStrings() > 1) {
  789. sender = words.First();
  790. if (sender.StartsWith(":") == true)
  791. sender.RemoveFirst(":");
  792. else if (sender.StartsWith("*:") == true)
  793. sender.RemoveFirst("*:");
  794. }
  795. return sender;
  796. }
  797. BString
  798. IrcProtocol::_LineCode(BStringList words)
  799. {
  800. BString code;
  801. if (words.CountStrings() > 2)
  802. code = words.StringAt(1);
  803. return code;
  804. }
  805. BStringList
  806. IrcProtocol::_LineParameters(BStringList words, BString line)
  807. {
  808. BStringList params;
  809. BString current;
  810. for (int i = 2; i < words.CountStrings(); i++)
  811. if ((current = words.StringAt(i)).StartsWith(":") == false)
  812. params.Add(current);
  813. else
  814. break;
  815. // Last parameter is preceded by a colon
  816. int32 index = line.RemoveChars(0, 1).FindFirst(" :");
  817. if (index != B_ERROR)
  818. params.Add(line.RemoveChars(0, index + 2));
  819. return params;
  820. }
  821. void
  822. IrcProtocol::_SendMsg(BMessage* msg)
  823. {
  824. msg->AddString("protocol", Signature());
  825. if (fReady == true)
  826. fMessenger->SendMessage(msg);
  827. else if (DEBUG_ENABLED == true) {
  828. std::cout << "Tried sending message when not ready: \n";
  829. msg->PrintToStream();
  830. }
  831. }
  832. void
  833. IrcProtocol::_SendIrc(BString cmd)
  834. {
  835. cmd << "\r\n";
  836. if (fSocket != NULL && fSocket->IsConnected() == true) {
  837. while (fWriteLocked == true)
  838. snooze(1000);
  839. fWriteLocked = true;
  840. fSocket->Write(cmd.String(), cmd.CountBytes(0, cmd.CountChars()));
  841. fWriteLocked = false;
  842. }
  843. else {
  844. BMessage disable(IM_MESSAGE);
  845. disable.AddInt32("im_what", IM_PROTOCOL_DISABLE);
  846. }
  847. }
  848. BString
  849. IrcProtocol::_SenderNick(BString sender)
  850. {
  851. BStringList split;
  852. sender.Split("!", true, split);
  853. return split.First();
  854. }
  855. BString
  856. IrcProtocol::_SenderIdent(BString sender)
  857. {
  858. BStringList split;
  859. sender.Split("!", true, split);
  860. return split.Last();
  861. }
  862. BString
  863. IrcProtocol::_IdentNick(BString ident)
  864. {
  865. bool found = false;
  866. BString nick = fIdentNicks.ValueFor(ident, &found);
  867. if (found == true)
  868. return nick;
  869. return ident;
  870. }
  871. BString
  872. IrcProtocol::_NickIdent(BString nick)
  873. {
  874. for (int i = 0; i < fIdentNicks.CountItems(); i++)
  875. if (fIdentNicks.ValueAt(i) == nick)
  876. return fIdentNicks.KeyAt(i);
  877. return nick;
  878. }
  879. bool
  880. IrcProtocol::_IsChannelName(BString name)
  881. {
  882. return (name.StartsWith("!") || name.StartsWith("&") || name.StartsWith("#")
  883. || name.StartsWith("+"));
  884. }
  885. #define disable_all_faces(current) { \
  886. if (bold > -1) _FormatToggleFace(msg, B_BOLD_FACE, &bold, current); \
  887. if (italics > -1) _FormatToggleFace(msg, B_ITALIC_FACE, &italics, current); \
  888. if (strike > -1) _FormatToggleFace(msg, B_STRIKEOUT_FACE, &strike, current); \
  889. if (underline > -1) _FormatToggleFace(msg, B_UNDERSCORE_FACE, &underline, current); \
  890. if (reverse > -1) _FormatToggleFace(msg, B_NEGATIVE_FACE, &reverse, current); \
  891. };
  892. #define disable_color(current) { \
  893. if (colorStart > -1) { \
  894. msg->AddInt32("color_start", colorStart); \
  895. msg->AddInt32("color_length", current - colorStart); \
  896. msg->AddColor("color", _IntToRgb(color)); \
  897. colorStart = -1; \
  898. color = -1; \
  899. } \
  900. };
  901. void
  902. IrcProtocol::_AddFormatted(BMessage* msg, const char* name, BString text)
  903. {
  904. BString newText;
  905. int32 italics = -1, bold = -1, underline = -1, strike = -1, mono = -1;
  906. int32 reverse = -1;
  907. int32 color = -1, colorStart = -1;
  908. int32 length = text.CountBytes(0, text.CountChars());
  909. for (int32 j=0, i=0; j < length; j++) {
  910. char c = text.ByteAt(j);
  911. switch (c) {
  912. case FORMAT_COLOR:
  913. {
  914. // Apply and reset previous color, if existant
  915. disable_color(i);
  916. char one = text.ByteAt(j + 1);
  917. char two = text.ByteAt(j + 2);
  918. // Try and get colors from either two-digits or one-digits
  919. int32 colorIndex = -1;
  920. if (isdigit(one) == true && isdigit(two) == true) {
  921. char num[3] = { one, two, '\0' };
  922. colorIndex = atoi(num);
  923. if (colorIndex >= 0 && colorIndex <= 99)
  924. j += 2;
  925. }
  926. else if (isdigit(one) == true) {
  927. char num[2] = { one, '\0' };
  928. colorIndex = atoi(num);
  929. if (colorIndex >= 0 && colorIndex <= 99)
  930. j++;
  931. }
  932. else
  933. break;
  934. // Use color if valid
  935. if (colorIndex >= 0 && colorIndex <= 99) {
  936. int colors[FORMAT_COLOR_COUNT] = FORMAT_COLORS;
  937. color = colors[colorIndex];
  938. colorStart = i;
  939. }
  940. // Ignore setting of background
  941. if (text.ByteAt(j + 1) == ',')
  942. if (isdigit(text.ByteAt(j+2)) && isdigit(text.ByteAt(j+3)))
  943. j += 3;
  944. else if (isdigit(text.ByteAt(j + 2)))
  945. j += 2;
  946. break;
  947. }
  948. case FORMAT_BOLD:
  949. _FormatToggleFace(msg, B_BOLD_FACE, &bold, i);
  950. break;
  951. case FORMAT_ITALIC:
  952. _FormatToggleFace(msg, B_ITALIC_FACE, &italics, i);
  953. break;
  954. case FORMAT_UNDERSCORE:
  955. _FormatToggleFace(msg, B_UNDERSCORE_FACE, &underline, i);
  956. break;
  957. case FORMAT_STRIKEOUT:
  958. _FormatToggleFace(msg, B_STRIKEOUT_FACE, &strike, i);
  959. break;
  960. case FORMAT_REVERSE:
  961. _FormatToggleFace(msg, B_NEGATIVE_FACE, &reverse, i);
  962. break;
  963. case FORMAT_RESET:
  964. disable_all_faces(i);
  965. disable_color(i);
  966. break;
  967. default:
  968. newText << c;
  969. i++;
  970. }
  971. }
  972. disable_all_faces(length);
  973. disable_color(length);
  974. msg->AddString(name, newText);
  975. }
  976. void
  977. IrcProtocol::_FormatToggleFace(BMessage* msg, uint16 face, int32* start,
  978. int32 current)
  979. {
  980. if (*start == -1)
  981. *start = current;
  982. else {
  983. msg->AddInt32("face_start", *start);
  984. msg->AddInt32("face_length", current - *start);
  985. msg->AddUInt16("face", face);
  986. *start = -1;
  987. }
  988. }
  989. void
  990. IrcProtocol::_UpdateContact(BString nick, BString ident, bool online)
  991. {
  992. if (fContacts.HasString(nick) == false)
  993. return;
  994. if (online == true && fOfflineContacts.HasString(nick) == true) {
  995. _RemoveContact(nick);
  996. _AddContact(ident);
  997. fOfflineContacts.Remove(nick);
  998. }
  999. else if (online == false && fOfflineContacts.HasString(nick) == false) {
  1000. fOfflineContacts.Add(nick);
  1001. }
  1002. }
  1003. void
  1004. IrcProtocol::_AddContact(BString nick)
  1005. {
  1006. fContacts.Add(nick);
  1007. BString user_id = _NickIdent(nick);
  1008. BMessage added(IM_MESSAGE);
  1009. added.AddInt32("im_what", IM_ROSTER);
  1010. added.AddString("user_id", user_id);
  1011. _SendMsg(&added);
  1012. if (user_id == nick)
  1013. fOfflineContacts.Add(nick);
  1014. }
  1015. void
  1016. IrcProtocol::_RemoveContact(BString user_id)
  1017. {
  1018. BString nick = _IdentNick(user_id);
  1019. fContacts.Remove(nick);
  1020. fOfflineContacts.Remove(nick);
  1021. BMessage removed(IM_MESSAGE);
  1022. removed.AddInt32("im_what", IM_ROSTER_CONTACT_REMOVED);
  1023. removed.AddString("user_id", _NickIdent(user_id));
  1024. _SendMsg(&removed);
  1025. }
  1026. void
  1027. IrcProtocol::_RenameContact(BString user_id, BString newNick)
  1028. {
  1029. BString oldNick = _IdentNick(user_id);
  1030. if (fContacts.HasString(oldNick) == true) {
  1031. fContacts.Remove(_IdentNick(user_id));
  1032. fOfflineContacts.Remove(_IdentNick(user_id));
  1033. fContacts.Add(newNick);
  1034. }
  1035. }
  1036. void
  1037. IrcProtocol::_LoadContacts()
  1038. {
  1039. BMessage contacts;
  1040. BFile file(_ContactsCache(), B_READ_ONLY);
  1041. if (file.InitCheck() == B_OK)
  1042. contacts.Unflatten(&file);
  1043. int i = 0;
  1044. BString user_name;
  1045. while (contacts.FindString("user_name", i, &user_name) == B_OK) {
  1046. _AddContact(user_name);
  1047. i++;
  1048. }
  1049. }
  1050. void
  1051. IrcProtocol::_SaveContacts()
  1052. {
  1053. BMessage contacts;
  1054. for (int i = 0; i < fContacts.CountStrings(); i++)
  1055. contacts.AddString("user_name", fContacts.StringAt(i));
  1056. BFile file(_ContactsCache(), B_WRITE_ONLY | B_CREATE_FILE);
  1057. if (file.InitCheck() == B_OK)
  1058. contacts.Flatten(&file);
  1059. }
  1060. int32
  1061. IrcProtocol::_RolePerms(UserRole role)
  1062. {
  1063. switch (role) {
  1064. case ROOM_HALFOP:
  1065. return PERM_READ | PERM_WRITE | PERM_NICK | PERM_KICK
  1066. | PERM_ROOM_SUBJECT;
  1067. case IRC_OPERATOR:
  1068. case ROOM_OPERATOR:
  1069. return PERM_READ | PERM_WRITE | PERM_NICK | PERM_KICK | PERM_BAN
  1070. | PERM_ROOM_SUBJECT | PERM_ROLECHANGE;
  1071. }
  1072. return PERM_READ | PERM_WRITE | PERM_NICK;
  1073. }
  1074. const char*
  1075. IrcProtocol::_RoleTitle(UserRole role)
  1076. {
  1077. switch (role) {
  1078. case ROOM_HALFOP:
  1079. return B_TRANSLATE("Half-Op");
  1080. case ROOM_OPERATOR:
  1081. return B_TRANSLATE("Operator");
  1082. case IRC_OPERATOR:
  1083. return B_TRANSLATE("IRC Wizard");
  1084. }
  1085. return B_TRANSLATE("Member");
  1086. }
  1087. const char*
  1088. IrcProtocol::_ContactsCache()
  1089. {
  1090. BPath path(AccountCachePath(fName));
  1091. path.Append("contact_list");
  1092. return path.Path();
  1093. }
  1094. void
  1095. IrcProtocol::_JoinDefaultRooms()
  1096. {
  1097. // Hardcoded default room… I'm so awful, aren't I? ;-)
  1098. if (fServer == "irc.oftc.net") {
  1099. BFile room(RoomCachePath(fName, "#haiku"), B_READ_ONLY);
  1100. if (room.InitCheck() != B_OK) {
  1101. BString cmd("JOIN #haiku");
  1102. _SendIrc(cmd);
  1103. }
  1104. }
  1105. }
  1106. BString
  1107. IrcProtocol::_ReadUntilNewline(BDataIO* io, BString* extraBuffer)
  1108. {
  1109. BString total;
  1110. char buf[1024] = { '\0' };
  1111. // Use buffer from last read if any text remains
  1112. if (extraBuffer->IsEmpty() == false) {
  1113. BString trimRet = _TrimStringToNewline(extraBuffer);
  1114. if (trimRet.IsEmpty() == true)
  1115. total << extraBuffer;
  1116. else
  1117. return trimRet;
  1118. }
  1119. while (!(strstr(buf, "\n"))) {
  1120. io->Read(buf, 1023);
  1121. total << buf;
  1122. if (DEBUG_ENABLED)
  1123. std::cerr << buf << std::endl;
  1124. }
  1125. BString currentLine = _TrimStringToNewline(&total);
  1126. extraBuffer->SetTo(total);
  1127. return currentLine;
  1128. }
  1129. BString
  1130. IrcProtocol::_TrimStringToNewline(BString* str)
  1131. {
  1132. BString line;
  1133. int32 lineEnd = str->FindFirst('\n');
  1134. if (lineEnd != B_ERROR) {
  1135. str->CopyCharsInto(line, 0, lineEnd + 1);
  1136. str->RemoveChars(0, lineEnd + 1);
  1137. }
  1138. return line;
  1139. }
  1140. rgb_color
  1141. IrcProtocol::_IntToRgb(int rgb)
  1142. {
  1143. uint8 r = rgb >> 16;
  1144. uint8 g = rgb >> 8 & 0xFF;
  1145. uint8 b = rgb & 0xFF;
  1146. return (rgb_color){r, g, b};
  1147. }
  1148. BMessage
  1149. IrcProtocol::_AccountTemplate()
  1150. {
  1151. BMessage settings;
  1152. BMessage server;
  1153. server.AddString("name", "server");
  1154. server.AddString("description", B_TRANSLATE("Server:"));
  1155. server.AddString("default", "irc.oftc.net");
  1156. server.AddString("error", B_TRANSLATE("Please enter a valid server address."));
  1157. server.AddInt32("type", B_STRING_TYPE);
  1158. settings.AddMessage("setting", &server);
  1159. BMessage port;
  1160. port.AddString("name", "port");
  1161. port.AddString("description", B_TRANSLATE("Port:"));
  1162. port.AddInt32("default", 6697);
  1163. port.AddString("error", B_TRANSLATE("We need a port-number to know which door to knock on! Likely 6667/6697."));
  1164. port.AddInt32("type", B_INT32_TYPE);
  1165. settings.AddMessage("setting", &port);
  1166. BMessage ssl;
  1167. ssl.AddString("name", "ssl");
  1168. ssl.AddString("description", B_TRANSLATE("SSL"));
  1169. ssl.AddBool("default", true);
  1170. ssl.AddInt32("type", B_BOOL_TYPE);
  1171. settings.AddMessage("setting", &ssl);
  1172. BMessage nick;
  1173. nick.AddString("name", "nick");
  1174. nick.AddString("description", B_TRANSLATE("Nickname:"));
  1175. nick.AddString("default", "Haikunaut");
  1176. nick.AddString("error", B_TRANSLATE("You need a default nickname― The Nameless are not welcome on IRC."));
  1177. nick.AddInt32("type", B_STRING_TYPE);
  1178. settings.AddMessage("setting", &nick);
  1179. BMessage ident;
  1180. ident.AddString("name", "ident");
  1181. ident.AddString("description", B_TRANSLATE("Username:"));
  1182. ident.AddString("error", B_TRANSLATE("You need a username in order to connect!"));
  1183. ident.AddInt32("type", B_STRING_TYPE);
  1184. settings.AddMessage("setting", &ident);
  1185. BMessage password;
  1186. password.AddString("name", "password");
  1187. password.AddString("description", B_TRANSLATE("Password:"));
  1188. password.AddInt32("type", B_STRING_TYPE);
  1189. settings.AddMessage("setting", &password);
  1190. BMessage realName;
  1191. realName.AddString("name", "real_name");
  1192. realName.AddString("description", B_TRANSLATE("Real name:"));
  1193. realName.AddInt32("type", B_STRING_TYPE);
  1194. realName.AddString("default", "Gord the Destroyer");
  1195. realName.AddString("error", B_TRANSLATE("A real name must be defined. (P.S.: You can lie!)"));
  1196. settings.AddMessage("setting", &realName);
  1197. BMessage part;
  1198. part.AddString("name", "part");
  1199. part.AddString("description", B_TRANSLATE("Part message:"));
  1200. part.AddInt32("type", B_STRING_TYPE);
  1201. part.AddString("default", "Chat-O-Matic[0.1]: i've been liquified!");
  1202. settings.AddMessage("setting", &part);
  1203. return settings;
  1204. }
  1205. BMessage
  1206. IrcProtocol::_RoomTemplate()
  1207. {
  1208. BMessage settings;
  1209. BMessage id;
  1210. id.AddString("name", "chat_id");
  1211. id.AddString("description", B_TRANSLATE("Channel:"));
  1212. id.AddString("error", B_TRANSLATE("Please enter a channel― skipping it doesn't make sense!"));
  1213. id.AddInt32("type", B_STRING_TYPE);
  1214. settings.AddMessage("setting", &id);
  1215. return settings;
  1216. }
  1217. BMessage
  1218. IrcProtocol::_RosterTemplate()
  1219. {
  1220. BMessage settings;
  1221. BMessage nick;
  1222. nick.AddString("name", "user_id");
  1223. nick.AddString("description", B_TRANSLATE("Nick:"));
  1224. nick.AddString("error", B_TRANSLATE("How can someone be your friend if you don't know their name?"));
  1225. nick.AddInt32("type", B_STRING_TYPE);
  1226. settings.AddMessage("setting", &nick);
  1227. return settings;
  1228. }