MessageAgent.cpp 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782
  1. /*
  2. * The contents of this file are subject to the Mozilla Public
  3. * License Version 1.1 (the "License"); you may not use this file
  4. * except in compliance with the License. You may obtain a copy of
  5. * the License at http://www.mozilla.org/MPL/
  6. *
  7. * Software distributed under the License is distributed on an "AS
  8. * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
  9. * implied. See the License for the specific language governing
  10. * rights and limitations under the License.
  11. *
  12. * The Original Code is Vision.
  13. *
  14. * The Initial Developer of the Original Code is The Vision Team.
  15. * Portions created by The Vision Team are
  16. * Copyright (C) 1999, 2000, 2001 The Vision Team. All Rights
  17. * Reserved.
  18. *
  19. * Contributor(s): Wade Majors <wade@ezri.org>
  20. * Rene Gollent
  21. * Todd Lair
  22. * Andrew Bazan
  23. * Jamie Wilkinson
  24. */
  25. #include <Beep.h>
  26. #include <Entry.h>
  27. #include <MenuItem.h>
  28. #include <Notification.h>
  29. #include <PopUpMenu.h>
  30. #include <Roster.h>
  31. #include <UTF8.h>
  32. #include "MessageAgent.h"
  33. #include "WindowList.h"
  34. #include "ClientWindow.h"
  35. #include "StatusView.h"
  36. #include "Utilities.h"
  37. #include "Vision.h"
  38. #include "VTextControl.h"
  39. #include <unistd.h>
  40. #include <stdlib.h>
  41. #include <sys/socket.h>
  42. #include <sys/select.h>
  43. #include <arpa/inet.h>
  44. MessageAgent::MessageAgent (
  45. BRect &frame_,
  46. const char *id_,
  47. const char *fServerName_,
  48. const BMessenger &fSMsgr_,
  49. const char *nick,
  50. const char *addyString,
  51. bool chat,
  52. bool initiate,
  53. const char *IP,
  54. const char *port)
  55. : ClientAgent (
  56. id_,
  57. fServerName_,
  58. nick,
  59. fSMsgr_,
  60. frame_),
  61. fChatAddy (addyString ? addyString : ""),
  62. fChatee (id_),
  63. fDIP (IP),
  64. fDPort (port),
  65. fDChat (chat),
  66. fDInitiate (initiate),
  67. fDConnected (false),
  68. fMySocket (0),
  69. fAcceptSocket(0)
  70. {
  71. Init();
  72. }
  73. MessageAgent::~MessageAgent (void)
  74. {
  75. fDConnected = false;
  76. if (fDChat)
  77. {
  78. if (fMySocket)
  79. close (fMySocket);
  80. if (fAcceptSocket)
  81. close (fAcceptSocket);
  82. }
  83. }
  84. void
  85. MessageAgent::AllAttached (void)
  86. {
  87. // initialize threads here since messenger will otherwise not be valid
  88. if (fDChat)
  89. {
  90. if (fDInitiate)
  91. fDataThread = spawn_thread(DCCIn, "DCC Chat(I)", B_NORMAL_PRIORITY, this);
  92. else
  93. fDataThread = spawn_thread(DCCOut, "DCC Chat(O)", B_NORMAL_PRIORITY, this);
  94. resume_thread (fDataThread);
  95. }
  96. ClientAgent::AllAttached();
  97. }
  98. void
  99. MessageAgent::AddMenuItems (BPopUpMenu *pMenu)
  100. {
  101. BMenuItem *item (NULL);
  102. item = new BMenuItem("Whois", new BMessage (M_MSG_WHOIS));
  103. item->SetTarget (this);
  104. if (Id().FindFirst (" [DCC]") >= 0) // dont enable for dcc sessions
  105. item->SetEnabled (false);
  106. pMenu->AddItem (item);
  107. BMessage *msg (new BMessage (M_SUBMIT));
  108. BString command ("/dcc send ");
  109. command += fId;
  110. msg->AddString ("input", command.String());
  111. item = new BMenuItem("DCC send", msg);
  112. item->SetTarget (this);
  113. if (Id().FindFirst (" [DCC]") >= 0) // dont enable for dcc sessions
  114. item->SetEnabled (false);
  115. pMenu->AddItem (item);
  116. pMenu->AddSeparatorItem();
  117. }
  118. void
  119. MessageAgent::Init (void)
  120. {
  121. // empty Init, call DCCServerSetup from input thread to avoid deadlocks
  122. }
  123. void
  124. MessageAgent::DCCServerSetup(void)
  125. {
  126. int32 myPort (atoi(vision_app->GetString ("dccMinPort")));
  127. int32 diff (atoi(vision_app->GetString ("dccMaxPort")) - myPort);
  128. if (diff > 0)
  129. myPort += rand() % diff;
  130. BString outNick (fChatee);
  131. outNick.RemoveFirst (" [DCC]");
  132. struct sockaddr_in sa;
  133. BMessage reply;
  134. fSMsgr.SendMessage (M_GET_IP, &reply);
  135. BString address;
  136. reply.FindString ("ip", &address);
  137. if (fDPort != "")
  138. myPort = atoi (fDPort.String());
  139. fMySocket = socket (AF_INET, SOCK_STREAM, 0);
  140. BMessage statMsg (M_DISPLAY);
  141. if (fMySocket < 0)
  142. {
  143. ClientAgent::PackDisplay (&statMsg, S_DCC_SOCKET_ERROR, C_ERROR);
  144. fMsgr.SendMessage (&statMsg);
  145. return;
  146. }
  147. sa.sin_family = AF_INET;
  148. sa.sin_addr.s_addr = INADDR_ANY;
  149. sa.sin_port = htons(myPort);
  150. if (bind (fMySocket, (struct sockaddr*)&sa, sizeof(sa)) == -1)
  151. {
  152. ClientAgent::PackDisplay (&statMsg, S_DCC_BIND_ERROR, C_ERROR);
  153. fMsgr.SendMessage (&statMsg);
  154. return;
  155. }
  156. BMessage sendMsg (M_SERVER_SEND);
  157. BString buffer;
  158. sa.sin_addr.s_addr = inet_addr (address.String());
  159. buffer << "PRIVMSG " << outNick << " :\1DCC CHAT chat ";
  160. buffer << htonl(sa.sin_addr.s_addr) << " ";
  161. buffer << myPort << "\1";
  162. sendMsg.AddString ("data", buffer.String());
  163. fSMsgr.SendMessage (&sendMsg);
  164. vision_app->AcquireDCCLock();
  165. listen (fMySocket, 1);
  166. BString dataBuffer;
  167. struct in_addr addr;
  168. addr.s_addr = inet_addr (address.String());
  169. dataBuffer << S_DCC_CHAT_LISTEN
  170. << address.String() << S_DCC_CHAT_PORT << myPort << "\n";
  171. ClientAgent::PackDisplay (&statMsg, dataBuffer.String(), C_TEXT);
  172. fMsgr.SendMessage (&statMsg);
  173. return;
  174. }
  175. status_t
  176. MessageAgent::DCCIn (void *arg)
  177. {
  178. MessageAgent *agent ((MessageAgent *)arg);
  179. BMessenger fSMsgrE (agent->fSMsgr);
  180. BMessenger mMsgr (agent);
  181. agent->DCCServerSetup();
  182. int dccSocket (agent->fMySocket);
  183. int dccAcceptSocket (0);
  184. struct sockaddr_in remoteAddy;
  185. int theLen (sizeof (struct sockaddr_in));
  186. dccAcceptSocket = accept(dccSocket, (struct sockaddr*)&remoteAddy, (socklen_t *)&theLen);
  187. vision_app->ReleaseDCCLock();
  188. if (dccAcceptSocket < 0)
  189. return B_ERROR;
  190. agent->fAcceptSocket = dccAcceptSocket;
  191. agent->fDConnected = true;
  192. BMessage msg (M_DISPLAY);
  193. ClientAgent::PackDisplay (&msg, S_DCC_CHAT_CONNECTED);
  194. mMsgr.SendMessage (&msg);
  195. char tempBuffer[2];
  196. BString inputBuffer;
  197. int32 recvReturn (0);
  198. struct fd_set rset, eset;
  199. FD_ZERO (&rset);
  200. FD_ZERO (&eset);
  201. FD_SET (dccAcceptSocket, &rset);
  202. FD_SET (dccAcceptSocket, &eset);
  203. while (mMsgr.IsValid() && agent->fDConnected)
  204. {
  205. if (select (dccAcceptSocket + 1, &rset, NULL, &eset, NULL) > 0)
  206. {
  207. if ((recvReturn = recv (dccAcceptSocket, tempBuffer, 1, 0)) == 0)
  208. {
  209. BMessage termMsg (M_DISPLAY);
  210. agent->fDConnected = false;
  211. ClientAgent::PackDisplay (&termMsg, S_DCC_CHAT_TERM);
  212. mMsgr.SendMessage (&termMsg);
  213. break;
  214. }
  215. if (recvReturn > 0)
  216. {
  217. if (tempBuffer[0] == '\n')
  218. {
  219. inputBuffer.RemoveLast ("\r");
  220. inputBuffer = FilterCrap (inputBuffer.String(), false);
  221. char convBuffer[2048];
  222. memset (convBuffer, 0, sizeof(convBuffer));
  223. int32 length (inputBuffer.Length()),
  224. destLength (sizeof(convBuffer)),
  225. state (0);
  226. int32 encoding = vision_app->GetInt32("encoding");
  227. if (encoding != B_UNICODE_CONVERSION)
  228. {
  229. convert_to_utf8 (
  230. encoding,
  231. inputBuffer.String(),
  232. &length,
  233. convBuffer,
  234. &destLength,
  235. &state);
  236. }
  237. else
  238. {
  239. if (IsValidUTF8(inputBuffer.String(), length))
  240. {
  241. strlcpy(convBuffer, inputBuffer.String(), length);
  242. destLength = strlen(convBuffer);
  243. }
  244. else
  245. {
  246. convert_to_utf8 (
  247. B_ISO1_CONVERSION,
  248. inputBuffer.String(),
  249. &length,
  250. convBuffer,
  251. &destLength,
  252. &state);
  253. }
  254. }
  255. BMessage dispMsg (M_CHANNEL_MSG);
  256. dispMsg.AddString ("msgz", convBuffer);
  257. mMsgr.SendMessage (&dispMsg);
  258. inputBuffer = "";
  259. }
  260. else
  261. inputBuffer.Append(tempBuffer[0],1);
  262. }
  263. }
  264. else if (FD_ISSET (dccAcceptSocket, &eset))
  265. {
  266. BMessage termMsg (M_DISPLAY);
  267. agent->fDConnected = false;
  268. ClientAgent::PackDisplay (&termMsg, S_DCC_CHAT_TERM);
  269. mMsgr.SendMessage (&termMsg);
  270. break;
  271. }
  272. FD_SET (dccAcceptSocket, &rset);
  273. FD_SET (dccAcceptSocket, &eset);
  274. }
  275. return 0;
  276. }
  277. status_t
  278. MessageAgent::DCCOut (void *arg)
  279. {
  280. MessageAgent *agent ((MessageAgent *)arg);
  281. BMessenger mMsgr (agent);
  282. struct sockaddr_in sa;
  283. int status;
  284. int dccAcceptSocket (0);
  285. char *endpoint;
  286. uint32 realIP = strtoul (agent->fDIP.String(), &endpoint, 10);
  287. if ((dccAcceptSocket = socket(AF_INET, SOCK_STREAM, 0)) < 0)
  288. {
  289. BMessage msg (M_DISPLAY);
  290. ClientAgent::PackDisplay (&msg, S_DCC_SOCKET_ERROR);
  291. mMsgr.SendMessage (&msg);
  292. return false;
  293. }
  294. agent->fAcceptSocket = dccAcceptSocket;
  295. sa.sin_family = AF_INET;
  296. sa.sin_port = htons (atoi (agent->fDPort.String()));
  297. sa.sin_addr.s_addr = ntohl (realIP);
  298. memset (sa.sin_zero, 0, sizeof(sa.sin_zero));
  299. {
  300. BMessage msg (M_DISPLAY);
  301. BString buffer;
  302. struct in_addr addr;
  303. addr.s_addr = ntohl (realIP);
  304. buffer << S_DCC_CHAT_TRY
  305. << inet_ntoa (addr)
  306. << S_DCC_CHAT_PORT << agent->fDPort << "\n";
  307. ClientAgent::PackDisplay (&msg, buffer.String());
  308. mMsgr.SendMessage (&msg);
  309. }
  310. status = connect (dccAcceptSocket, (struct sockaddr *)&sa, sizeof(sa));
  311. if (status < 0)
  312. {
  313. BMessage msg (M_DISPLAY);
  314. ClientAgent::PackDisplay (&msg, S_DCC_CONN_ERROR);
  315. mMsgr.SendMessage (&msg);
  316. close (agent->fMySocket);
  317. return false;
  318. }
  319. agent->fDConnected = true;
  320. BMessage msg (M_DISPLAY);
  321. ClientAgent::PackDisplay (&msg, S_DCC_CHAT_CONNECTED);
  322. mMsgr.SendMessage (&msg);
  323. char tempBuffer[2];
  324. BString inputBuffer;
  325. int32 recvReturn (0);
  326. struct fd_set rset, eset;
  327. struct timeval tv = { 0, 0 };
  328. FD_ZERO (&rset);
  329. FD_ZERO (&eset);
  330. FD_SET (dccAcceptSocket, &rset);
  331. FD_SET (dccAcceptSocket, &eset);
  332. while (mMsgr.IsValid() && agent->fDConnected)
  333. {
  334. if (select (dccAcceptSocket + 1, &rset, NULL, &eset, &tv) > 0)
  335. {
  336. if ((recvReturn = recv (dccAcceptSocket, tempBuffer, 1, 0)) == 0)
  337. {
  338. BMessage termMsg (M_DISPLAY);
  339. agent->fDConnected = false;
  340. ClientAgent::PackDisplay (&termMsg, S_DCC_CHAT_TERM);
  341. mMsgr.SendMessage (&termMsg);
  342. break;
  343. }
  344. if (recvReturn > 0)
  345. {
  346. if (tempBuffer[0] == '\n')
  347. {
  348. inputBuffer.RemoveLast ("\r");
  349. inputBuffer = FilterCrap (inputBuffer.String(), false);
  350. char convBuffer[2048];
  351. memset (convBuffer, 0, sizeof(convBuffer));
  352. int32 length (inputBuffer.Length()),
  353. destLength (sizeof(convBuffer)),
  354. state (0);
  355. convert_to_utf8 (
  356. vision_app->GetInt32("encoding"), inputBuffer.String(),
  357. &length,
  358. convBuffer,
  359. &destLength,
  360. &state);
  361. BMessage dispMsg (M_CHANNEL_MSG);
  362. dispMsg.AddString ("msgz", inputBuffer.String());
  363. mMsgr.SendMessage (&dispMsg);
  364. inputBuffer = "";
  365. }
  366. else
  367. inputBuffer.Append(tempBuffer[0],1);
  368. }
  369. }
  370. else if (FD_ISSET (dccAcceptSocket, &eset))
  371. {
  372. BMessage termMsg (M_DISPLAY);
  373. agent->fDConnected = false;
  374. ClientAgent::PackDisplay (&termMsg, S_DCC_CHAT_TERM);
  375. mMsgr.SendMessage (&termMsg);
  376. break;
  377. }
  378. else
  379. snooze (20000);
  380. FD_SET (dccAcceptSocket, &rset);
  381. FD_SET (dccAcceptSocket, &eset);
  382. }
  383. return 0;
  384. }
  385. void
  386. MessageAgent::ChannelMessage (
  387. const char *msgz,
  388. const char *nick,
  389. const char *ident,
  390. const char *address)
  391. {
  392. // fAgentWinItem->SetName (nick);
  393. ClientAgent::ChannelMessage (msgz, nick, ident, address);
  394. }
  395. void
  396. MessageAgent::MessageReceived (BMessage *msg)
  397. {
  398. switch (msg->what)
  399. {
  400. case B_SIMPLE_DATA:
  401. {
  402. if (msg->HasRef("refs"))
  403. {
  404. // TODO: get this to work properly for multiple refs
  405. // and update DCC send logic to figure that out too
  406. entry_ref ref;
  407. msg->FindRef("refs", &ref);
  408. BMessage dccmsg(M_CHOSE_FILE);
  409. dccmsg.AddString("nick", fChatee.String());
  410. dccmsg.AddRef("refs", &ref);
  411. fSMsgr.SendMessage(&dccmsg);
  412. }
  413. }
  414. break;
  415. case M_CHANNEL_MSG:
  416. {
  417. const char *nick (NULL);
  418. if (msg->HasString ("nick"))
  419. {
  420. msg->FindString ("nick", &nick);
  421. BString outNick (nick);
  422. outNick.RemoveFirst (" [DCC]");
  423. if (fMyNick.ICompare (outNick) != 0 && !fDChat)
  424. fAgentWinItem->SetName (outNick.String());
  425. msg->ReplaceString ("nick", outNick.String());
  426. }
  427. else
  428. {
  429. BString outNick (fChatee.String());
  430. outNick.RemoveFirst (" [DCC]");
  431. msg->AddString ("nick", outNick.String());
  432. }
  433. BWindow *window (Window());
  434. if (IsHidden())
  435. UpdateStatus (WIN_NICK_BIT);
  436. if (IsHidden() || (window && !window->IsActive()))
  437. {
  438. BNotification notification(B_INFORMATION_NOTIFICATION);
  439. notification.SetGroup(BString("Vision"));
  440. entry_ref ref = vision_app->AppRef();
  441. notification.SetOnClickFile(&ref);
  442. notification.SetTitle(fServerName.String());
  443. BString tempString(msg->FindString("msgz"));
  444. if (tempString[0] == '\1')
  445. {
  446. tempString.RemoveFirst("\1ACTION ");
  447. tempString.RemoveLast ("\1");
  448. }
  449. BString content;
  450. content.SetToFormat("%s said: %s", nick, tempString.String());
  451. notification.SetContent(content);
  452. notification.Send();
  453. }
  454. if (window != NULL && !window->IsActive())
  455. system_beep(kSoundEventNames[(uint32)seNickMentioned]);
  456. // Send the rest of processing up the chain
  457. ClientAgent::MessageReceived (msg);
  458. }
  459. break;
  460. case M_MSG_WHOIS:
  461. {
  462. BMessage dataSend (M_SERVER_SEND);
  463. AddSend (&dataSend, "WHOIS ");
  464. AddSend (&dataSend, fChatee.String());
  465. AddSend (&dataSend, " ");
  466. AddSend (&dataSend, fChatee.String());
  467. AddSend (&dataSend, endl);
  468. }
  469. case M_CHANGE_NICK:
  470. {
  471. const char *oldNick, *newNick;
  472. msg->FindString ("oldnick", &oldNick);
  473. msg->FindString ("newnick", &newNick);
  474. if (fChatee.ICompare (oldNick) == 0)
  475. {
  476. const char *address;
  477. const char *ident;
  478. msg->FindString ("address", &address);
  479. msg->FindString ("ident", &ident);
  480. BString oldId (fId);
  481. fChatee = fId = newNick;
  482. if (fDChat)
  483. fId.Append(" [DCC]");
  484. // set up new logging file for new nick
  485. BMessage logMsg (M_UNREGISTER_LOGGER);
  486. logMsg.AddString("name", oldId.String());
  487. fSMsgr.SendMessage(&logMsg);
  488. logMsg.MakeEmpty();
  489. logMsg.what = M_REGISTER_LOGGER;
  490. logMsg.AddString("name", fId.String());
  491. fSMsgr.SendMessage(&logMsg);
  492. fAgentWinItem->SetName (fId.String());
  493. ClientAgent::MessageReceived (msg);
  494. }
  495. else if (fMyNick.ICompare (oldNick) == 0)
  496. {
  497. if (!IsHidden())
  498. vision_app->pClientWin()->pStatusView()->SetItemValue (STATUS_NICK, newNick);
  499. ClientAgent::MessageReceived (msg);
  500. }
  501. }
  502. break;
  503. case M_STATUS_ADDITEMS:
  504. {
  505. vision_app->pClientWin()->pStatusView()->AddItem (new StatusItem (
  506. 0, ""),
  507. true);
  508. vision_app->pClientWin()->pStatusView()->AddItem (new StatusItem (
  509. "Lag: ",
  510. "",
  511. STATUS_ALIGN_LEFT),
  512. true);
  513. vision_app->pClientWin()->pStatusView()->AddItem (new StatusItem (
  514. 0,
  515. "",
  516. STATUS_ALIGN_LEFT),
  517. true);
  518. // The false bool for SetItemValue() tells the StatusView not to Invalidate() the view.
  519. // We send true on the last SetItemValue().
  520. vision_app->pClientWin()->pStatusView()->SetItemValue (STATUS_SERVER, fServerName.String(), false);
  521. vision_app->pClientWin()->pStatusView()->SetItemValue (STATUS_LAG, fMyLag.String(), false);
  522. vision_app->pClientWin()->pStatusView()->SetItemValue (STATUS_NICK, fMyNick.String(), true);
  523. }
  524. break;
  525. default:
  526. ClientAgent::MessageReceived (msg);
  527. }
  528. }
  529. void
  530. MessageAgent::ActionMessage (const char *msg, const char *nick)
  531. {
  532. if (!fDChat)
  533. ClientAgent::ActionMessage (msg, nick);
  534. else if (fDConnected)
  535. {
  536. BString outTemp;
  537. outTemp = "\1ACTION ";
  538. outTemp += msg;
  539. outTemp += "\1";
  540. outTemp += "\n";
  541. char convBuffer[2048];
  542. memset (convBuffer, 0, sizeof(convBuffer));
  543. int32 length (outTemp.Length()),
  544. destLength (sizeof(convBuffer)),
  545. state (0);
  546. convert_from_utf8 (
  547. vision_app->GetInt32("encoding"),
  548. outTemp.String(),
  549. &length,
  550. convBuffer,
  551. &destLength,
  552. &state);
  553. if (send(fAcceptSocket, convBuffer, destLength, 0) < 0)
  554. {
  555. fDConnected = false;
  556. Display (S_DCC_CHAT_TERM);
  557. return;
  558. }
  559. outTemp.RemoveLast ("\n");
  560. ChannelMessage (outTemp.String(), nick);
  561. }
  562. }
  563. void
  564. MessageAgent::Parser (const char *buffer)
  565. {
  566. if (!fDChat)
  567. {
  568. BMessage dataSend (M_SERVER_SEND);
  569. AddSend (&dataSend, "PRIVMSG ");
  570. AddSend (&dataSend, fChatee);
  571. AddSend (&dataSend, " :");
  572. AddSend (&dataSend, buffer);
  573. AddSend (&dataSend, endl);
  574. }
  575. else if (fDConnected)
  576. {
  577. BString outTemp (buffer);
  578. outTemp << "\n";
  579. char convBuffer[2048];
  580. memset (convBuffer, 0, sizeof(convBuffer));
  581. int32 length (outTemp.Length()),
  582. destLength (sizeof(convBuffer)),
  583. state (0);
  584. convert_from_utf8 (
  585. vision_app->GetInt32("encoding"),
  586. outTemp.String(),
  587. &length,
  588. convBuffer,
  589. &destLength,
  590. &state);
  591. if (send(fAcceptSocket, convBuffer, destLength, 0) < 0)
  592. {
  593. fDConnected = false;
  594. Display (S_DCC_CHAT_TERM);
  595. return;
  596. }
  597. }
  598. else
  599. return;
  600. Display ("<", C_MYNICK);
  601. Display (fMyNick.String(), C_NICKDISPLAY);
  602. Display ("> ", C_MYNICK);
  603. BString sBuffer (buffer);
  604. Display (sBuffer.String());
  605. Display ("\n");
  606. }
  607. void
  608. MessageAgent::DroppedFile (BMessage *)
  609. {
  610. // TODO: implement this when DCC's ready
  611. }
  612. void
  613. MessageAgent::TabExpansion (void)
  614. {
  615. int32 start,
  616. finish;
  617. fInput->TextView()->GetSelection (&start, &finish);
  618. if (fInput->TextView()->TextLength()
  619. && start == finish
  620. && start == fInput->TextView()->TextLength())
  621. {
  622. const char *fInputText (
  623. fInput->TextView()->Text()
  624. + fInput->TextView()->TextLength());
  625. const char *place (fInputText);
  626. while (place > fInput->TextView()->Text())
  627. {
  628. if (*(place - 1) == '\x20')
  629. break;
  630. --place;
  631. }
  632. BString insertion;
  633. if (!fId.ICompare (place, strlen (place)))
  634. {
  635. insertion = fId;
  636. insertion.RemoveLast(" [DCC]");
  637. }
  638. else if (!fMyNick.ICompare (place, strlen (place)))
  639. insertion = fMyNick;
  640. if (insertion.Length())
  641. {
  642. fInput->TextView()->Delete (
  643. place - fInput->TextView()->Text(),
  644. fInput->TextView()->TextLength());
  645. fInput->TextView()->Insert (insertion.String());
  646. fInput->TextView()->Select (
  647. fInput->TextView()->TextLength(),
  648. fInput->TextView()->TextLength());
  649. }
  650. }
  651. }