home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 13 / AACD13.ISO / AACD / Online / StrICQ / Src / STRICQChat.c < prev    next >
C/C++ Source or Header  |  2000-02-16  |  43KB  |  1,588 lines

  1. /*
  2.  
  3. STRICQ - An Amiga, MUI Based, ICQ Clone.
  4. Copyright (C) 1998-2000 Douglas F. McLaughlin
  5.  
  6. This program is free software; you can redistribute it and/or
  7. modify it under the terms of the GNU General Public License
  8. as published by the Free Software Foundation; either version 2
  9. of the License, or (at your option) any later version.
  10.  
  11. This program is distributed in the hope that it will be useful,
  12. but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14. GNU General Public License for more details.
  15.  
  16. You should have received a copy of the GNU General Public License
  17. along with this program; if not, write to the Free Software
  18. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  19.  
  20. Douglas F. McLaughlin - stricq@owlnet.net
  21.  
  22. */
  23.  
  24. #include <sys/types.h>
  25.  
  26. #include <stdio.h>
  27. #include <stdlib.h>
  28. #include <netdb.h>
  29. #include <time.h>
  30.  
  31. #include <libraries/asl.h>
  32. #include <libraries/asyncio.h>
  33. #include <libraries/icq.h>
  34.  
  35. #include <bsdsocket/socketbasetags.h>
  36.  
  37. #include <sys/errno.h>
  38. #include <sys/ioctl.h>
  39. #include <sys/socket.h>
  40.  
  41. #include <proto/asyncio.h>
  42. #include <proto/dos.h>
  43. #include <proto/exec.h>
  44. #include <proto/graphics.h>
  45. #include <proto/socket.h>
  46. #include <proto/utility.h>
  47.  
  48. #include "STRICQMUI.h"
  49.  
  50. #define MUIM_STRICQ_AddSocks TAG_USER+1
  51.  
  52. extern void Add2Log(UBYTE, ULONG, UWORD, BOOL, UWORD, char *, ULONG);
  53. extern void AddUser2CList(struct Contact *);
  54. extern struct Contact *GetContact(ULONG);
  55. extern void DelSockets(UWORD);
  56. extern char *GetNick(ULONG);
  57. extern struct Sockets *GetSocketFmContact(struct Contact *, UBYTE);
  58. extern struct Sockets *GetSocketFmSocket(UWORD);
  59. extern struct Sockets *GetSocketFmPort(UWORD);
  60. extern void HandleError(UBYTE, char *, ...);
  61. extern LONG OpenTCPSocket(struct Contact *, UBYTE, ULONG, ULONG);
  62. extern void PrepNewContact(struct Contact *);
  63. extern void PrepTCPMessage(struct TCP_Message *, ULONG);
  64. extern void revmemcpy(char *, char *, int);
  65. extern LONG SendTCPPacket(ULONG, UWORD, char *, UWORD, UWORD);
  66.  
  67. APTR __asm AddSession(REG(a2) APTR, REG(a1) struct ChatSession *);
  68. void __asm RemSession(REG(a2) APTR, REG(a1) struct ChatSession *);
  69. LONG __asm CmpSession(REG(a1) struct ChatSession *, REG(a2) struct ChatSession *);
  70. void __asm DisplaySession(REG(a2) char **, REG(a1) struct ChatSession *);
  71.  
  72. ULONG __asm ChatDispatcher(REG(a0) struct IClass *cl, REG(a2) Object *obj, REG(a1) Msg msg);
  73.  
  74. void __asm OpenChatReqWin(REG(a2) APTR);
  75. void __asm SendChatReq(REG(a2) APTR);
  76. void __asm EndChat(REG(a2) APTR);
  77. void __asm ChatWinState(REG(a2) APTR);
  78. void __asm EndAllChat(REG(a2) APTR);
  79. void __asm SetBIU(REG(a2) APTR);
  80. void __asm SetLocalFColor(REG(a2) APTR);
  81.  
  82. void SendChatInit(UWORD);
  83. BOOL StartChat(struct Contact *, struct Sockets *, BOOL);
  84. void StartRemoteChat(struct Sockets *, struct Sockets *, struct Contact *);
  85. char *GetSessionNicks(struct Sockets *);
  86. int recv_chat(char *, UWORD);
  87. void DoChatMode(char *, int, UWORD);
  88. void UpdateChatSession(struct Contact *, struct Sockets *);
  89. struct ChatSession *GetChatSessionPort(UWORD);
  90. ULONG CountChatPorts(struct Sockets *);
  91. void SaveChatText(struct Contact *, struct ChatWin *, struct RemoteChatObj *);
  92. void SendText(UWORD, char *, UWORD);
  93.  
  94. void mChatHandleEvent(struct IClass *, Object *, struct MUIP_HandleEvent *);
  95.  
  96. enum {CB_SLEEP = 0, CB_OVERRIDE, CB_X1, CB_BACK, CB_TEXT, CB_X2, CB_BOLD, CB_ITALIC, CB_UNDERLINE, CB_X3,
  97.       CB_CHATMODE, CB_X4, CB_KEYCLICK, CB_X5, CB_ACTIONS, CB_EMOTIONS};
  98.  
  99. enum {CB_COMMANDS = 0, CB_FREEZE, CB_CLEAR, CB_X10, CB_TIMEZONE};
  100.  
  101. extern char err_buf[], currentdir[], *ChatColorNames[];
  102. extern LONG cmap[];
  103. extern UBYTE ChatColors[16][3];
  104. extern ULONG TCP_Seq, AsyncBuf;
  105. extern UWORD TCPCodes[];
  106. extern struct Colors Pens;
  107. extern struct ObjApp *app;
  108.  
  109. struct MUIP_STRICQ_AddSocks {
  110.   ULONG MethodID;
  111.   struct Sockets *Socks;
  112. };
  113.  
  114.  
  115. APTR __asm AddSession(REG(a2) APTR pool, REG(a1) struct ChatSession *chat)
  116.  
  117. {
  118.  
  119. struct ChatSession *newchat = NULL;
  120.  
  121. if (!(newchat = AllocPooled(pool,sizeof(struct ChatSession)))) return(NULL);
  122.  
  123. strcpy(newchat->Session,chat->Session);
  124.  
  125. newchat->ChatListen = chat->ChatListen;
  126.  
  127. return(newchat);
  128.  
  129. }
  130.  
  131.  
  132. void __asm RemSession(REG(a2) APTR pool, REG(a1) struct ChatSession *chat)
  133.  
  134. {
  135.  
  136. FreePooled(pool,chat,sizeof(struct ChatSession));
  137.  
  138. return;
  139.  
  140. }
  141.  
  142.  
  143. LONG __asm CmpSession(REG(a1) struct ChatSession *a1, REG(a2) struct ChatSession *a2)
  144.  
  145. {
  146.  
  147. if (a1->ChatListen < a2->ChatListen) return(-1);
  148. if (a1->ChatListen > a2->ChatListen) return(1);
  149.  
  150. return(0);
  151.  
  152. }
  153.  
  154.  
  155. void __asm DisplaySession(REG(a2) char **array, REG(a1) struct ChatSession *chat)
  156.  
  157. {
  158.  
  159. static char buf[10];
  160.  
  161. if (chat) {
  162.   sprintf(buf,"%d",chat->ChatListen);
  163.   *array++ = buf;
  164.   *array   = chat->Session;
  165. }
  166. else {
  167.   *array++ = "Port";
  168.   *array   = "Current Chat Sessions";
  169. }
  170.  
  171. return;
  172.  
  173. }
  174.  
  175.  
  176. void __asm OpenChatReqWin(REG(a2) APTR obj)
  177.  
  178. {
  179.  
  180. static char nick[21];
  181.  
  182. ULONG uin, total;
  183.  
  184. get(obj,MUIA_UserData,&uin);
  185.  
  186. strcpy(nick,GetNick(uin));
  187.  
  188. set(app->WI_ChatReqOut,MUIA_Window_Title,nick);
  189.  
  190. set(app->BT_SendChat,MUIA_UserData,uin);
  191. set(app->BT_JoinChat,MUIA_UserData,uin);
  192.  
  193. get(app->LV_Sessions,MUIA_NList_Entries,&total);
  194.  
  195. if (total == 0) set(app->BT_JoinChat,MUIA_Disabled,TRUE);
  196. else set(app->BT_JoinChat,MUIA_Disabled,FALSE);
  197.  
  198. set(app->WI_ChatReqOut,MUIA_Window_Open,TRUE);
  199.  
  200. return;
  201.  
  202. }
  203.  
  204.  
  205. void __asm SendChatReq(REG(a2) APTR obj)
  206.  
  207. {
  208.  
  209. char *msg, *sess_nicks, *TCP_Buf = NULL;
  210.  
  211. LONG sel;
  212.  
  213. ULONG id, Seq;
  214.  
  215. UWORD len, RevLen, ret, session = 0;
  216.  
  217. struct ChatSession *chat;
  218. struct Contact *user;
  219. struct TCP_Message TCPMsg;
  220.  
  221. sess_nicks = LINE;
  222.  
  223. if (obj == app->BT_JoinChat) {
  224.   get(app->LV_Sessions,MUIA_NList_Active,&sel);
  225.   if (sel == MUIV_NList_Active_Off) {
  226.     HandleError(DBG_OTH_FATL,"You must choose a chat session to 'Join'.");
  227.     return;
  228.   }
  229.   DoMethod(app->LV_Sessions,MUIM_NList_GetEntry,sel,&chat);
  230.   if (chat) {
  231.     session = chat->ChatListen;
  232.     sess_nicks = chat->Session;
  233.   }
  234. }
  235.  
  236. get(obj,MUIA_UserData,&id);
  237.  
  238. if (!(user = GetContact(id))) return;
  239.  
  240. if (!user->UWin) return;
  241.  
  242. user->ChatListen = session;
  243.  
  244. if (session) user->ConnectMe = TRUE;
  245.  
  246. get(app->TI_ChatReason,MUIA_Textinput_Contents,&msg);
  247.  
  248. set(app->WI_ChatReqOut,MUIA_Window_Open,FALSE);
  249.  
  250. TCPMsg.Command = TCP_MESSAGE;
  251. TCPMsg.Type = MSG_CHAT;
  252. TCPMsg.MsgCommand = TCP_MSG_REAL;
  253.  
  254. PrepTCPMessage(&TCPMsg,id);
  255.  
  256. TCPMsg.Message = msg;
  257.  
  258. TCPMsg.Chat_Session = sess_nicks;
  259. TCPMsg.Chat_RevPort = TCPMsg.Chat_Port = user->ChatListen;
  260. TCPMsg.Chat_X2 = 0;
  261.  
  262. len = TCP_CreateMsgPacket(&TCPMsg,&TCP_Buf,&Seq,&RevLen);
  263.  
  264. if (!(ret = SendTCPPacket(id,TCP_MESSAGE,TCP_Buf,len,RevLen))) {
  265.   HandleError(DBG_TCP_ERRS,"Could not send Chat Request to %s.",user->Nick);
  266.   TCP_FreeMsgPacket(TCP_Buf);
  267.   return;
  268. }
  269.  
  270. set(app->TI_ChatReason,MUIA_Textinput_Contents,NULL);
  271.  
  272. if (ret == -1) Add2Log(LOG_CLIENT,Seq,TCP_MESSAGE,FALSE,len,TCP_Buf,id);
  273. else Add2Log(LOG_CLIENT,Seq,TCP_MESSAGE,FALSE,0,NULL,id);
  274.  
  275. TCP_FreeMsgPacket(TCP_Buf);
  276.  
  277. return;
  278.  
  279. }
  280.  
  281.  
  282. void SendChatInit(UWORD sock)
  283.  
  284. {
  285.  
  286. char buf[50], *nick;
  287.  
  288. UWORD len, revlen;
  289.  
  290. struct Contact *user;
  291. struct Sockets *socks;
  292.  
  293. struct TCP_ChatInit Init;
  294.  
  295. if (!(socks = GetSocketFmSocket(sock))) return;
  296.  
  297. if (!(user = GetContact(socks->UIN))) return;
  298.  
  299. get(app->STR_ICQUIN,MUIA_String_Integer,&Init.UIN);
  300. get(app->STR_Nick,MUIA_String_Contents,&nick);
  301.  
  302. Init.HandShake = TCP_CHAT_HANDSHAKE;
  303. Init.HiVersion = TCP_CHAT_VER_CURRENT;
  304. strcpy(Init.Nick,nick);
  305. Init.RevPort = user->ChatListen;
  306. Init.TextColor = 0x00FFFFFF;
  307. Init.BackColor = 0x00000000;
  308. Init.X1 = 0x00;
  309.  
  310. HandleError(DBG_TCP_DBUG,"SendChatInit()");
  311.  
  312. len = TCP_CreateChatPacket(TCP_CHAT_1,&Init,buf,&revlen);
  313.  
  314. send(sock,(char *)&revlen,2,0);
  315. send(sock,buf,len,0);
  316.  
  317. socks->Timehack = time(NULL);
  318. socks->ConnectPort = user->ChatListen;
  319.  
  320. return;
  321.  
  322. }
  323.  
  324.  
  325. void ParseChatPkt(char *buf, int len, UWORD sock)
  326.  
  327. {
  328.  
  329. APTR Data = NULL;
  330.  
  331. char cbuf[1024];
  332.  
  333. int i;
  334.  
  335. UBYTE Cmd;
  336.  
  337. ULONG opt = 1, sess_count;
  338.  
  339. UWORD RevLen, Len;
  340.  
  341. struct Contact *user, User;
  342. struct Sockets *socks, *sock2, *primesocks;
  343.  
  344. struct TCP_Init Init;
  345.  
  346. if (socks = GetSocketFmSocket(sock)) {
  347.   user = GetContact(socks->UIN);
  348.   socks->Timehack = time(NULL);
  349. }
  350.  
  351. PrintHex(DBG_TCP_PKTS,"Chat packet",buf,len);
  352.  
  353. if (!socks->HadInit) {
  354.   if (!TCP_ParseTCPInit(&Init,buf)) return;
  355.   if (!(user = GetContact(Init.UIN))) {
  356.     PrepNewContact(&User);
  357.     User.UIN = Init.UIN;
  358.     sprintf(cbuf,"%ld",Init.UIN);
  359.     User.Nick = cbuf;
  360.     User.Status = STATUS_NEWUIN;
  361.     User.CanTCP = Init.TCP_Flag;
  362.     AddUser2CList(&User);
  363.     user = GetContact(Init.UIN);
  364.   }
  365.   user->ChatListen = socks->ConnectPort;
  366.   socks->TCP_Version = Init.Version;
  367.   socks->TCP_Revision = Init.X1;
  368.   socks->TCP_Listen_Msg_Port = Init.TCP_MsgPort;
  369.   socks->TCP_Listen_Other_Port = Init.TCP_Chat_File_Port;
  370.   socks->UIN = user->UIN;
  371.   socks->TCP_Flag = Init.TCP_Flag;
  372.   socks->HadInit = TRUE;
  373.   DoMethod(app->LV_SockList,MUIM_NList_Redraw,MUIV_NList_Redraw_All);
  374.   return;
  375. }
  376.  
  377. primesocks = GetSocketFmPort(user->ChatListen);
  378.  
  379. Cmd = TCP_ParseChatPacket(&Data,buf);
  380.  
  381. switch(Cmd) {
  382.   case TCP_CHAT_1: {
  383.     char *nick;
  384. //  int i;
  385.     ULONG total;
  386. //  struct Sockets *sock2;
  387.     struct TCP_ChatInit *Init = Data;
  388.     struct TCP_ChatTwo Two;
  389.     struct TCP_ChatTwo_Ext *ext_p1, *ext_p2;
  390.     socks->TCP_ChatHandShake = Init->HandShake;
  391.     get(app->STR_ICQUIN,MUIA_String_Integer,&total);
  392.     get(app->STR_Nick,MUIA_String_Contents,&nick);
  393.     Two.HandShake = TCP_CHAT_HANDSHAKE;
  394.     Two.UIN = total;
  395.     strcpy(Two.Nick,nick);
  396.     Two.TextColor = 0x00FFFFFF;
  397.     Two.BackColor = 0x00000000;
  398.     Two.Version = TCP_VERSION_CURRENT;
  399.     Two.X1 = TCP_REVISION_CURRENT;
  400.     Two.Port = socks->ConnectPort;
  401.     Two.IP = socks->LocalAddr.sin_addr.s_addr;
  402.     Two.RealIP = socks->LocalAddr.sin_addr.s_addr;
  403.     Two.TCP_Flag = TCP_FLAG_CAPABLE;
  404.     Two.X2 = 0x6A6C;
  405.     Two.FontSize = 0x00000008;
  406.     Two.FontFamily = 0x00000000;
  407.     strcpy(Two.FontName,"Courier");
  408.     Two.X3 = 0x00;
  409.     Two.X4 = 0x02;
  410.     Two.Ext.Next = NULL;
  411.     ext_p2 = &Two.Ext;
  412.     sess_count = CountChatPorts(primesocks);
  413.     Two.Count = sess_count-1;
  414.     if (sess_count > 1) {
  415.       get(app->LV_SockList,MUIA_NList_Entries,&total);
  416.       for(i = 0; i < total; i++) {
  417.         DoMethod(app->LV_SockList,MUIM_NList_GetEntry,i,&sock2);
  418.         if (sock2) {
  419.           if (sock2->ConnectPort == primesocks->Port && sock2 != socks && sock2 != primesocks) {
  420.             HandleError(DBG_TCP_DBUG,"Adding socket %d to the TCP_CHAT_2 struct",sock2->Socket);
  421.             if (!(ext_p1 = (struct TCP_ChatTwo_Ext *)AllocVec(sizeof(struct TCP_ChatTwo_Ext),MEMF_CLEAR))) break;
  422.             ext_p2->Next = ext_p1;
  423.             ext_p1->Next = NULL;
  424.             ext_p1->Version = sock2->TCP_Version;
  425.             ext_p1->X1 = sock2->TCP_Revision;
  426.             ext_p1->Port = sock2->TCP_Listen_Other_Port;
  427.             ext_p1->UIN = sock2->UIN;
  428.             ext_p1->IP = sock2->Address.sin_addr.s_addr;
  429.             ext_p1->RealIP = sock2->Address.sin_addr.s_addr;
  430.             ext_p1->RevPort = sock2->TCP_Listen_Other_Port;
  431.             ext_p1->TCP_Flag = sock2->TCP_Flag;
  432.             ext_p1->X2 = sock2->TCP_ChatData;
  433.             ext_p1->HandShake = sock2->TCP_ChatHandShake;
  434.             ext_p2 = ext_p1;
  435.           }
  436.         }
  437.       }
  438.     }
  439.     HandleError(DBG_TCP_DBUG,"About to create TCP_CHAT_2");
  440.     Len = TCP_CreateChatPacket(TCP_CHAT_2,&Two,cbuf,&RevLen);
  441.     send(sock,(char *)&RevLen,2,0);
  442.     send(sock,cbuf,Len,0);
  443.     if (Two.Ext.Next) {
  444.       ext_p1 = Two.Ext.Next;
  445.       while(ext_p1) {
  446.         ext_p2 = ext_p1->Next;
  447.         FreeVec(ext_p1);
  448.         ext_p1 = ext_p2;
  449.       }
  450.       Two.Ext.Next = NULL;
  451.     }
  452.     break;
  453.   }
  454.   case TCP_CHAT_2: {
  455.     struct TCP_ChatThree Three;
  456.     struct TCP_ChatTwo *Two = Data;
  457.     struct TCP_ChatTwo_Ext *ext_p1, *ext_p2;
  458.     socks->TCP_Version = Two->Version;
  459.     socks->TCP_Revision = Two->X1;
  460.     socks->TCP_Listen_Other_Port = Two->Port;
  461.     socks->TCP_Flag = Two->TCP_Flag;
  462.     socks->TCP_ChatData = Two->X2;
  463.     socks->TCP_ChatHandShake = Two->HandShake;
  464.     ext_p2 = &Two->Ext;
  465.     while(ext_p1 = ext_p2->Next) {
  466.       struct Contact *user2;
  467.       if (!(user2 = GetContact(ext_p1->UIN))) {
  468.         PrepNewContact(&User);
  469.         User.UIN = ext_p1->UIN;
  470.         sprintf(cbuf,"%ld",ext_p1->UIN);
  471.         User.Nick = cbuf;
  472.         User.Status = STATUS_NEWUIN;
  473.         User.CanTCP = ext_p1->TCP_Flag;
  474.         AddUser2CList(&User);
  475.         user2 = GetContact(ext_p1->UIN);
  476.       }
  477.       if (!user2->ChatListen) {
  478.         user2->ChatListen = socks->ConnectPort;
  479.         user2->IP = ext_p1->IP;
  480.         user2->RealIP = ext_p1->RealIP;
  481.         HandleError(DBG_TCP_DBUG,"Also adding %s to multichat.",user2->Nick);
  482.         if (!OpenTCPSocket(user2,SOCK_CHAT,user2->IP,ext_p1->RevPort)) {
  483.           if (!OpenTCPSocket(user2,SOCK_CHAT,user2->RealIP,ext_p1->RevPort)) HandleError(DBG_TCP_ERRS,"Could not open a chat connection to %s.",user->Nick);
  484.         }
  485.       }
  486.       ext_p2 = ext_p1;
  487.     }
  488.     Three.Version = TCP_VERSION_CURRENT;
  489.     Three.X1 = TCP_REVISION_CURRENT;
  490.     Three.Port = socks->ConnectPort;
  491.     Three.IP = socks->LocalAddr.sin_addr.s_addr;
  492.     Three.RealIP = socks->LocalAddr.sin_addr.s_addr;
  493.     Three.TCP_Flag = TCP_FLAG_CAPABLE;
  494.     Three.X2 = 0x6A6C;
  495.     Three.FontSize = 0x00000008;
  496.     Three.FontFamily = 0x00000000;
  497.     strcpy(Three.FontName,"Courier");
  498.     Three.X3 = 0x0002;
  499.     HandleError(DBG_TCP_DBUG,"About to create TCP_CHAT_3");
  500.     Len = TCP_CreateChatPacket(TCP_CHAT_3,&Three,cbuf,&RevLen);
  501.     send(sock,(char *)&RevLen,2,0);
  502.     send(sock,cbuf,Len,0);
  503.     if (!primesocks->CWin) {
  504.       if (!StartChat(user,primesocks,FALSE)) {
  505.         DelSockets(sock);
  506.         break;
  507.       }
  508.     }
  509.     StartRemoteChat(socks,primesocks,user);
  510.     setsockopt(sock,IPPROTO_TCP,TCP_NODELAY,&opt,sizeof(opt));
  511.     socks->ChatMode = user;
  512.     break;
  513.   }
  514.   case TCP_CHAT_3: {
  515.     struct TCP_ChatThree *Three = Data;
  516.     socks->TCP_Version = Three->Version;
  517.     socks->TCP_Revision = Three->X1;
  518.     socks->TCP_Listen_Other_Port = Three->Port;
  519.     socks->TCP_Flag = Three->TCP_Flag;
  520.     socks->TCP_ChatData = Three->X2;
  521.     send(sock,"\004",1,0);
  522.     send(sock,"\003",1,0);
  523.     if (!primesocks->CWin) {
  524.       if (!StartChat(user,primesocks,FALSE)) {
  525.         DelSockets(sock);
  526.         break;
  527.       }
  528.     }
  529.     StartRemoteChat(socks,primesocks,user);
  530.     socks->ChatMode = user;
  531.     setsockopt(sock,IPPROTO_TCP,TCP_NODELAY,&opt,sizeof(opt));
  532.     break;
  533.   }
  534.   default:
  535.     PrintHex(DBG_TCP_ERRS,"Unknown Chat Init packet",buf,len);
  536. }
  537.  
  538. if (Data) FreeVec(Data);
  539.  
  540. return;
  541.  
  542. }
  543.  
  544.  
  545. BOOL StartChat(struct Contact *user, struct Sockets *primesocks, BOOL open)
  546.  
  547. {
  548.  
  549. char *nick;
  550.  
  551. static char Image_fl[MAXNAMLEN], Select_fl[MAXNAMLEN], Ghost_fl[MAXNAMLEN];
  552.  
  553. time_t t;
  554.  
  555. struct ChatWin *CWin;
  556. struct Sockets *socks;
  557.  
  558. static struct MUIP_Toolbar_Description TBDesc[] = {
  559.   {TDT_BUTTON, 's' , TDF_GHOSTED, "Sleep"    , "Sets your Chat Mode\nstatus to 'Away'"       , 0},
  560.   {TDT_BUTTON, 'o' , TDF_GHOSTED, "Override" , "Overrides the other user's\nfont/color prefs", 0},
  561.   {TDT_SPACE , NULL, NULL       , NULL       , NULL                                          , 0},
  562.   {TDT_BUTTON, NULL, TDF_GHOSTED, "Back"     , "Set the background color\n(Has no effect)"   , 0},
  563.   {TDT_BUTTON, 'f' , NULL       , "Text"     , "Set the current font color"                  , 0},
  564.   {TDT_SPACE , NULL, NULL       , NULL       , NULL                                          , 0},
  565.   {TDT_BUTTON, 'b' , TDF_TOGGLE , "Bold"     , "Set text to Bold"                            , 0},
  566.   {TDT_BUTTON, 'i' , TDF_TOGGLE , "Italic"   , "Set text to Italic"                          , 0},
  567.   {TDT_BUTTON, 'u' , TDF_TOGGLE , "Underline", "Set text to Underline"                       , 0},
  568.   {TDT_SPACE , NULL, NULL       , NULL       , NULL                                          , 0},
  569.   {TDT_BUTTON, 'w' , TDF_GHOSTED, "Chat Mode", "Set window mode to either\nSplit or IRC"     , 0}, 
  570.   {TDT_SPACE , NULL, NULL       , NULL       , NULL                                          , 0},
  571.   {TDT_BUTTON, 'c' , TDF_GHOSTED, "Keyclick" , "Toggle keyclick on/off"                      , 0},
  572.   {TDT_SPACE , NULL, NULL       , NULL       , NULL                                          , 0},
  573.   {TDT_BUTTON, 'a' , TDF_GHOSTED, "Actions"  , "Send an action line"                         , 0},
  574.   {TDT_BUTTON, 'e' , TDF_GHOSTED, "Emotions" , "Send an emotion line"                        , 0},
  575.   {TDT_BUTTON, 'm' , TDF_GHOSTED, "Smileys"  , "Send a smiley"                               , 0},
  576.  
  577.   {TDT_END, NULL, NULL, NULL, NULL, NULL},
  578. };
  579.  
  580. HandleError(DBG_TCP_DBUG,"StartChat()");
  581.  
  582. socks = GetSocketFmContact(user,SOCK_CHAT);
  583.  
  584. if (primesocks->CWin) {
  585.   if (open) set(primesocks->CWin->WI_ChatWin,MUIA_Window_Open,TRUE);
  586.   return(TRUE);
  587. }
  588.  
  589. if (!(CWin = (struct ChatWin *)AllocVec(sizeof(struct ChatWin),MEMF_CLEAR))) {
  590.   HandleError(DBG_OTH_FATL,"Failed to AllocVec %d bytes (struct ChatWin)",sizeof(struct ChatWin));
  591.   return(FALSE);
  592. }
  593.  
  594. sprintf(Image_fl,"%sImages/ChatBarN.iff",currentdir);
  595. sprintf(Select_fl,"%sImages/ChatBarS.iff",currentdir);
  596. sprintf(Ghost_fl,"%sImages/ChatBarG.iff",currentdir);
  597.  
  598. get(app->STR_Nick,MUIA_String_Contents,&nick);
  599.  
  600. t = time(NULL);
  601.  
  602. strcpy(CWin->Title,nick);
  603. sprintf(CWin->LocalTime,"Local Time: %.5s",ctime(&t)+11);
  604.  
  605. CWin->SC_ScrollBar = ScrollbarObject, End;
  606.  
  607. CWin->WI_ChatWin = WindowObject,
  608.   MUIA_Window_Title, CWin->Title,
  609.   MUIA_Window_ID, user->UIN | 0x20000000,
  610.   MUIA_UserData, user->UIN,
  611.   WindowContents, VGroup,
  612.     Child, ScrollgroupObject,
  613.       MUIA_Scrollgroup_FreeVert, FALSE,
  614.       MUIA_Scrollgroup_Contents, HGroupV,
  615. //      MUIA_Frame, MUIV_Frame_Virtual,
  616.         Child, CWin->TB_ChatBar = ToolbarObject,
  617.           MUIA_Toolbar_Description, TBDesc,
  618.           MUIA_Toolbar_ImageType, MUIV_Toolbar_ImageType_File,
  619.           MUIA_Toolbar_ImageNormal, Image_fl,
  620.           MUIA_Toolbar_ImageSelect, Select_fl,
  621.           MUIA_Toolbar_ImageGhost, Ghost_fl,
  622.           MUIA_ShortHelp, TRUE,
  623.         End,
  624.         Child, CWin->POP_FColors = PopobjectObject,
  625.           MUIA_Popstring_String, VSpace(0),
  626.           MUIA_Popstring_Button, VSpace(0),
  627.           MUIA_Popobject_ObjStrHook, &SetLocalFColorHook,
  628.           MUIA_Popobject_Object, CWin->LV_FColorList = NListviewObject,
  629.             MUIA_NListview_NList, NListObject,
  630.               MUIA_Frame, MUIV_Frame_String,
  631.               MUIA_NList_PrivateData, user->UIN,
  632.               MUIA_NList_ConstructHook, MUIV_NList_ConstructHook_String,
  633.               MUIA_NList_DestructHook, MUIV_NList_DestructHook_String,
  634.               MUIA_NList_SourceArray, ChatColorNames,
  635.               MUIA_NList_AdjustWidth, TRUE,
  636.               MUIA_NList_AdjustHeight, TRUE,
  637.             End,
  638.           End,
  639.         End,
  640.         Child, Label("Font"),
  641.         Child, CWin->POP_ChatFont = PopaslObject,
  642.           MUIA_Popasl_Type, ASL_FontRequest,
  643.           MUIA_Popstring_String, CWin->STR_ChatFont = String("",80),
  644.           MUIA_Popstring_Button, PopButton(MUII_PopUp),
  645.           ASLFO_TitleText, "Please select a font...",
  646.         End,
  647.       End,
  648.     End,
  649.     Child, VGroup,
  650.       MUIA_Frame, MUIV_Frame_Group,
  651.       Child, HGroup,
  652.         Child, TextObject,
  653.           MUIA_Text_Contents, "My Chat view",
  654.         End,
  655.         Child, CWin->TX_LocalTime = TextObject,
  656.           MUIA_Text_PreParse, "\033r",
  657.           MUIA_Text_Contents, CWin->LocalTime,
  658.         End,
  659.       End,
  660.       Child, HGroup,
  661.         MUIA_Group_Spacing, 0,
  662.         Child, CWin->TE_ChatLocal = NewObject(mcc_Chat->mcc_Class,NULL,
  663.           MUIA_Frame, MUIV_Frame_String,
  664. //        MUIA_Font, MUIV_Font_Tiny,
  665.           MUIA_CycleChain, TRUE,
  666.           MUIA_TextEditor_ExportHook, MUIV_TextEditor_ExportHook_Plain,
  667.           MUIA_TextEditor_Slider, CWin->SC_ScrollBar,
  668.           MUIA_TextEditor_ColorMap, cmap,
  669.         End,
  670.         Child, CWin->SC_ScrollBar,
  671.       End,
  672.     End,
  673.     Child, BalanceObject, End,
  674.     Child, CWin->GP_ChatGroups = HGroup,
  675.       Child, CWin->RT_Dummy = RectangleObject, End,
  676.     End,
  677.   End,
  678. End;
  679.  
  680. if (!CWin->WI_ChatWin) {
  681.   HandleError(DBG_OTH_FATL,"Could not create the initial chat window.");
  682.   FreeVec(CWin);
  683.   CWin = NULL;
  684.   return(FALSE);
  685. }
  686.  
  687. DoMethod(app->App,OM_ADDMEMBER,CWin->WI_ChatWin);
  688.  
  689. DoMethod(CWin->TE_ChatLocal,MUIM_STRICQ_AddSocks,primesocks);
  690.  
  691. DoMethod(CWin->WI_ChatWin,MUIM_Notify,MUIA_Window_CloseRequest,TRUE,CWin->WI_ChatWin,2,
  692.   MUIM_CallHook,&EndAllChatHook);
  693.  
  694. DoMethod(CWin->WI_ChatWin,MUIM_Notify,MUIA_Window_Activate,MUIV_EveryTime,CWin->WI_ChatWin,2,
  695.   MUIM_CallHook,&ChatWinStateHook);
  696.  
  697. DoMethod(CWin->TB_ChatBar,MUIM_Toolbar_Notify,CB_BOLD,MUIV_Toolbar_Notify_Pressed,MUIV_EveryTime,CWin->TE_ChatLocal,3,
  698.   MUIM_Set,MUIA_TextEditor_StyleBold,MUIV_TriggerValue);
  699.  
  700. DoMethod(CWin->TB_ChatBar,MUIM_Toolbar_Notify,CB_BOLD,MUIV_Toolbar_Notify_Pressed,MUIV_EveryTime,CWin->WI_ChatWin,2,
  701.   MUIM_CallHook,&SetBIUHook);
  702.  
  703. DoMethod(CWin->TB_ChatBar,MUIM_Toolbar_Notify,CB_ITALIC,MUIV_Toolbar_Notify_Pressed,MUIV_EveryTime,CWin->TE_ChatLocal,3,
  704.   MUIM_Set,MUIA_TextEditor_StyleItalic,MUIV_TriggerValue);
  705.  
  706. DoMethod(CWin->TB_ChatBar,MUIM_Toolbar_Notify,CB_ITALIC,MUIV_Toolbar_Notify_Pressed,MUIV_EveryTime,CWin->WI_ChatWin,2,
  707.   MUIM_CallHook,&SetBIUHook);
  708.  
  709. DoMethod(CWin->TB_ChatBar,MUIM_Toolbar_Notify,CB_UNDERLINE,MUIV_Toolbar_Notify_Pressed,MUIV_EveryTime,CWin->TE_ChatLocal,3,
  710.   MUIM_Set,MUIA_TextEditor_StyleUnderline,MUIV_TriggerValue);
  711.  
  712. DoMethod(CWin->TB_ChatBar,MUIM_Toolbar_Notify,CB_UNDERLINE,MUIV_Toolbar_Notify_Pressed,MUIV_EveryTime,CWin->WI_ChatWin,2,
  713.   MUIM_CallHook,&SetBIUHook);
  714.  
  715. DoMethod(CWin->TB_ChatBar,MUIM_Toolbar_Notify,CB_TEXT,MUIV_Toolbar_Notify_Pressed,FALSE,CWin->POP_FColors,1,
  716.   MUIM_Popstring_Open);
  717.  
  718. DoMethod(CWin->LV_FColorList,MUIM_Notify,MUIA_NList_EntryClick,MUIV_EveryTime,CWin->POP_FColors,2,
  719.   MUIM_Popstring_Close,TRUE);
  720.  
  721. set(CWin->WI_ChatWin,MUIA_Window_ActiveObject,CWin->TE_ChatLocal);
  722.  
  723. if (open) set(CWin->WI_ChatWin,MUIA_Window_Open,TRUE);
  724.  
  725. primesocks->CWin = CWin;
  726.  
  727. return(TRUE);
  728.  
  729. }
  730.  
  731.  
  732. ULONG __asm ChatDispatcher(REG(a0) struct IClass *cl, REG(a2) Object *obj, REG(a1) Msg msg)
  733.  
  734. {
  735.  
  736. int i;
  737.  
  738. switch(msg->MethodID) {
  739.   case MUIM_Setup: {
  740.     struct ChatData *data = INST_DATA(cl,obj);
  741.     data->Events.ehn_Priority = 0;
  742.     data->Events.ehn_Flags = 0;
  743.     data->Events.ehn_Events = IDCMP_VANILLAKEY;
  744.     data->Events.ehn_Object = obj;
  745.     data->Events.ehn_Class = cl;
  746.     DoMethod(_win(obj),MUIM_Window_AddEventHandler,&data->Events);
  747.     HandleError(DBG_TCP_DBUG,"Finished MUIM_Setup");
  748.     break;
  749.   }
  750.   case MUIM_Show:
  751.     for(i = 0; i < NUM_CHAT_COLORS; i++) cmap[i] = MUIPEN(Pens.ChatColors[i]);
  752.     break;
  753.   case MUIM_HandleEvent:
  754.     mChatHandleEvent(cl,obj,(struct MUIP_HandleEvent *)msg);
  755.     break;
  756.   case MUIM_Cleanup: { 
  757.     struct ChatData *data = INST_DATA(cl,obj);
  758.     DoMethod(_win(obj),MUIM_Window_RemEventHandler,&data->Events);
  759.     HandleError(DBG_TCP_DBUG,"Finished MUIM_Cleanup");
  760.     break;
  761.   }
  762.   case MUIM_STRICQ_AddSocks: {
  763.     struct ChatData *data = INST_DATA(cl,obj);
  764.     data->Socks = ((struct MUIP_STRICQ_AddSocks *)msg)->Socks;
  765.     HandleError(DBG_TCP_DBUG,"MUIM_STRICQ_AddSocks");
  766.     return(TRUE);
  767.   }
  768. //default:
  769. //  HandleError(DBG_TCP_DBUG,"Unknown ChatDispatcher Method");
  770. }
  771.  
  772. return(DoSuperMethodA(cl,obj,msg));
  773.  
  774. }
  775.  
  776.  
  777. void mChatHandleEvent(struct IClass *cl, Object *obj, struct MUIP_HandleEvent *msg)
  778.  
  779. {
  780.  
  781. BOOL flag = FALSE, *bold, *italic, *underline;
  782.  
  783. char key[2], text[16], *notifycmd;
  784.  
  785. LONG pen;
  786.  
  787. struct Sockets *primesocks;
  788.  
  789. struct ChatData *data = INST_DATA(cl,obj);
  790.  
  791. //HandleError(DBG_TCP_DBUG,"mChatHandleEvent()");
  792.  
  793. primesocks = data->Socks;
  794.  
  795. key[1] = '\0';
  796.  
  797. if (msg->imsg) {
  798.   switch(msg->imsg->Class) {
  799.     case IDCMP_VANILLAKEY:
  800.       set(primesocks->CWin->WI_ChatWin,MUIA_Window_ActiveObject,primesocks->CWin->TE_ChatLocal);
  801.       DoMethod(primesocks->CWin->TE_ChatLocal,MUIM_TextEditor_ARexxCmd,"POSITION EOF");
  802.       key[0] = (char)msg->imsg->Code;
  803.       switch(key[0]) {
  804.         case 0x07:
  805.           flag = TRUE;
  806.           get(app->STR_ChatBeep,MUIA_String_Contents,¬ifycmd);
  807.           if (strlen(notifycmd) > 0) System(notifycmd,NULL);
  808.           else DisplayBeep(NULL);
  809.           break;
  810.         case 0x08:
  811.           flag = TRUE;
  812.           DoMethod(primesocks->CWin->TE_ChatLocal,MUIM_TextEditor_ARexxCmd,"BACKSPACE");
  813.           break;
  814.         case 0x0d:
  815.           flag = TRUE;
  816.           key[0] = '\n';
  817.           DoMethod(primesocks->CWin->TE_ChatLocal,MUIM_TextEditor_InsertText,key,MUIV_TextEditor_InsertText_Bottom);
  818.           key[0] = '\x0d';
  819.           break;
  820.         default:
  821.           if ((UBYTE)key[0] >= (UBYTE)' ') {
  822.             flag = TRUE;
  823.             text[0] = '\0';
  824.             get(primesocks->CWin->TE_ChatLocal,MUIA_TextEditor_StyleBold,&bold);
  825.             get(primesocks->CWin->TE_ChatLocal,MUIA_TextEditor_StyleItalic,&italic);
  826.             get(primesocks->CWin->TE_ChatLocal,MUIA_TextEditor_StyleUnderline,&underline);
  827.             get(primesocks->CWin->TE_ChatLocal,MUIA_TextEditor_Pen,&pen);
  828.             if (bold) strcat(text,"\33b");
  829.             if (italic) strcat(text,"\33i");
  830.             if (underline) strcat(text,"\33u");
  831.             sprintf(text,"%s\33p[%ld]%s\33n",text,pen,key);
  832.             DoMethod(primesocks->CWin->TE_ChatLocal,MUIM_TextEditor_InsertText,text,MUIV_TextEditor_InsertText_Bottom);
  833.           }
  834.           break;
  835.       }
  836.       break;
  837.   }
  838. }
  839.  
  840. if (flag) SendText(primesocks->Port,key,1);
  841.  
  842. return;
  843.  
  844. }
  845.  
  846.  
  847. void StartRemoteChat(struct Sockets *socks, struct Sockets *primesocks, struct Contact *user)
  848.  
  849. {
  850.  
  851. BOOL *open;
  852.  
  853. static char Image_fl[MAXNAMLEN], Select_fl[MAXNAMLEN], Ghost_fl[MAXNAMLEN];
  854.  
  855. time_t t;
  856.  
  857. struct RemoteChatObj *RCObj;
  858.  
  859. static struct MUIP_Toolbar_Description RTBDesc[] = {
  860.   {TDT_BUTTON, NULL, TDF_GHOSTED, "Commands" , "Additional commands to\nperform with this UIN", 0},
  861.   {TDT_BUTTON, NULL, TDF_TOGGLE , "Freeze"   , "Freeze incoming text"                         , 0},
  862.   {TDT_BUTTON, NULL, NULL       , "Clear"    , "Clears the text"                              , 0},
  863.   {TDT_SPACE , NULL, NULL       , NULL       , NULL                                           , 0},
  864.   {TDT_BUTTON, NULL, TDF_GHOSTED, "Timezone" , "Sets remote user's timezone"                  , 0},
  865.  
  866.   {TDT_END, NULL, NULL, NULL, NULL, NULL},
  867. };
  868.  
  869. HandleError(DBG_TCP_DBUG,"StartRemoteChat()");
  870.  
  871. get(primesocks->CWin->WI_ChatWin,MUIA_Window_Open,&open);
  872.  
  873. if (open) DoMethod(primesocks->CWin->GP_ChatGroups,MUIM_Group_InitChange);
  874.  
  875. if (socks->RCObj) HandleError(DBG_TCP_ERRS,"Found a RemoteChatObj in the beginning of StartRemoteChat().  Please report this.");
  876.  
  877. if (!(RCObj = (struct RemoteChatObj *)AllocVec(sizeof(struct RemoteChatObj),MEMF_CLEAR))) {
  878.   HandleError(DBG_OTH_FATL,"Failed to AllocVec %d bytes (struct RemoteChatObj)",sizeof(struct RemoteChatObj));
  879.   return;
  880. }
  881.  
  882. sprintf(Image_fl,"%sImages/ChatBar2N.iff",currentdir);
  883. sprintf(Select_fl,"%sImages/ChatBar2S.iff",currentdir);
  884. sprintf(Ghost_fl,"%sImages/ChatBar2G.iff",currentdir);
  885.  
  886. t = time(NULL);
  887.  
  888. strcpy(RCObj->Nick,user->Nick);
  889. sprintf(RCObj->RemoteTime,"Remote Time: %.5s",ctime(&t)+11);
  890.  
  891. RCObj->SC_ScrollBar = ScrollbarObject, End;
  892.  
  893. RCObj->GP_RemoteObj = VGroup,
  894.   MUIA_Frame, MUIV_Frame_Group,
  895.   MUIA_UserData, user->UIN,
  896.   Child, HGroup,
  897.     Child, RCObj->TX_Nick = TextObject,
  898.       MUIA_Text_Contents, RCObj->Nick,
  899.       MUIA_Weight, 0,
  900.     End,
  901.     Child, RCObj->TB_RemoteChatBar = ToolbarObject,
  902.       MUIA_Toolbar_Description, RTBDesc,
  903.       MUIA_Toolbar_ImageType, MUIV_Toolbar_ImageType_File,
  904.       MUIA_Toolbar_ImageNormal, Image_fl,
  905.       MUIA_Toolbar_ImageSelect, Select_fl,
  906.       MUIA_Toolbar_ImageGhost, Ghost_fl,
  907.       MUIA_ShortHelp, TRUE,
  908.       MUIA_HorizDisappear, 2,
  909.     End,
  910.     Child, RCObj->TX_RemoteTime = TextObject,
  911.       MUIA_Text_PreParse, "\033r",
  912.       MUIA_Text_Contents, RCObj->RemoteTime,
  913.       MUIA_HorizDisappear, 1,
  914.     End,
  915.   End,
  916.   Child, HGroup,
  917.     MUIA_Group_Spacing, 0,
  918.     Child, RCObj->TE_ChatRemote = TextEditorObject,
  919.       MUIA_Frame, MUIV_Frame_String,
  920. //    MUIA_Font, MUIV_Font_Tiny,
  921.       MUIA_TextEditor_Slider, RCObj->SC_ScrollBar,
  922.       MUIA_TextEditor_ColorMap, cmap,
  923.     End,
  924.     Child, RCObj->SC_ScrollBar,
  925.   End,
  926. End;
  927.  
  928. if (!RCObj->GP_RemoteObj) {
  929.   HandleError(DBG_OTH_FATL,"Could not create a Remote Chat Object");
  930.   FreeVec(RCObj);
  931.   RCObj = NULL;
  932.   return;
  933. }
  934.  
  935. set(primesocks->CWin->RT_Dummy,MUIA_ShowMe,FALSE);
  936.  
  937. DoMethod(primesocks->CWin->GP_ChatGroups,OM_ADDMEMBER,RCObj->GP_RemoteObj);
  938.  
  939. if (open) DoMethod(primesocks->CWin->GP_ChatGroups,MUIM_Group_ExitChange);
  940. else set(primesocks->CWin->WI_ChatWin,MUIA_Window_Open,TRUE);
  941.  
  942. get(primesocks->CWin->WI_ChatWin,MUIA_Window_Open,&open);
  943.  
  944. if (!open) HandleError(DBG_OTH_FATL,"Chat window could not be opened!");
  945.  
  946. socks->RCObj = RCObj;
  947.  
  948. DoMethod(RCObj->TB_RemoteChatBar,MUIM_Toolbar_Notify,CB_FREEZE,MUIV_Toolbar_Notify_Pressed,MUIV_EveryTime,RCObj->TE_ChatRemote,3,
  949.   MUIM_Set,MUIA_TextEditor_Quiet,MUIV_TriggerValue);
  950.  
  951. DoMethod(RCObj->TB_RemoteChatBar,MUIM_Toolbar_Notify,CB_CLEAR,MUIV_Toolbar_Notify_Pressed,FALSE,RCObj->TE_ChatRemote,1,
  952.   MUIM_TextEditor_ClearText);
  953.  
  954. UpdateChatSession(user,primesocks);
  955.  
  956. return;
  957.  
  958. }
  959.  
  960.  
  961. char *GetSessionNicks(struct Sockets *primesocks)
  962.  
  963. {
  964.  
  965. static char nicks[256];
  966.  
  967. char *nick;
  968.  
  969. int i;
  970.  
  971. ULONG total;
  972.  
  973. struct Sockets *socks;
  974.  
  975. HandleError(DBG_TCP_DBUG,"GetSessionNicks(%d)",primesocks->Port);
  976.  
  977. get(app->LV_SockList,MUIA_NList_Entries,&total);
  978.  
  979. if (total < 1) return(NULL);
  980.  
  981. get(app->STR_Nick,MUIA_String_Contents,&nick);
  982.  
  983. strcpy(nicks,nick);
  984.  
  985. for(i = 0; i < total; i++) {
  986.   DoMethod(app->LV_SockList,MUIM_NList_GetEntry,i,&socks);
  987.   if (socks) {
  988.     if (socks->ConnectPort == primesocks->Port && socks != primesocks) {
  989.       HandleError(DBG_TCP_DBUG,"Socket %d has ConnectPort %d",socks->Socket,socks->ConnectPort);
  990.       sprintf(nicks,"%s, %s",nicks,GetNick(socks->UIN));
  991.     }
  992.   }
  993. }
  994.  
  995. if (strlen(nicks) == 0) return(NULL);
  996.  
  997. return(nicks);
  998.  
  999. }
  1000.  
  1001.  
  1002. int recv_chat(char *buf, UWORD sock)
  1003.  
  1004. {
  1005.  
  1006. int i;
  1007.  
  1008. ULONG err;
  1009.  
  1010. i = recv(sock,buf,TCPBUFLEN,0);
  1011.  
  1012. if (i == 0) return(-1);
  1013.  
  1014. if (i < 0) {
  1015.   switch(err = Errno()) {
  1016.     case EWOULDBLOCK:
  1017.     case EBADF:
  1018.       i = 0;
  1019.       break;
  1020.     default:
  1021.       SocketBaseTags(SBTM_GETREF(SBTC_ERRNOSTRPTR),&err,TAG_DONE);
  1022.       HandleError(DBG_TCP_ERRS,"Error on chat socket %d: %s\n",sock,(char *)err);
  1023.   }
  1024. }
  1025.  
  1026. return(i);
  1027.  
  1028. }
  1029.  
  1030.  
  1031. void DoChatMode(char *buf, int len, UWORD sock)
  1032.  
  1033. {
  1034.  
  1035. BOOL *bold, *italic, *underline;
  1036.  
  1037. char *notifycmd, key[2], text[16], *font;
  1038.  
  1039. int i;
  1040.  
  1041. LONG pen;
  1042.  
  1043. UWORD flen;
  1044.  
  1045. struct Sockets *socks;
  1046.  
  1047. socks = GetSocketFmSocket(sock);
  1048.  
  1049. PrintHex(DBG_TCP_PKTS,"Chat mode data",buf,len);
  1050.  
  1051. key[1] = '\0';
  1052.  
  1053. for(i = 0; i<len; i++) {
  1054.   DoMethod(socks->RCObj->TE_ChatRemote,MUIM_TextEditor_ARexxCmd,"POSITION EOF");
  1055.   switch(buf[i]) {
  1056.     case 0x07: //Beep
  1057.       get(app->STR_ChatBeep,MUIA_String_Contents,¬ifycmd);
  1058.       if (strlen(notifycmd) > 0) System(notifycmd,NULL);
  1059.       else DisplayBeep(NULL);
  1060.       break;
  1061.     case 0x12: //Font Size
  1062.       i += 4;
  1063.       break;
  1064.     case 0x01: //Background Color
  1065.       i += 4;
  1066.       break;
  1067.     case TCP_CHAT_CMD_FCOLOR: {
  1068.       int j;
  1069.       for(j = 0; j < NUM_CHAT_COLORS; j++) {
  1070.         if ((UBYTE)buf[i+1] == ChatColors[j][0] && (UBYTE)buf[i+2] == ChatColors[j][1] && (UBYTE)buf[i+3] == ChatColors[j][2]) break;
  1071.       }
  1072.       if (j == NUM_CHAT_COLORS) j = -1;
  1073.       set(socks->RCObj->TE_ChatRemote,MUIA_TextEditor_Pen,j+1);
  1074.       i += 4;
  1075.       break;
  1076.     }
  1077.     case TCP_CHAT_CMD_STYLE: {
  1078.       struct TCP_ChatCmdStyle Style;
  1079.       Style.Bold = (buf[++i]&TCP_CHATF_BOLD?TRUE:FALSE);
  1080.       Style.Italic = (buf[i]&TCP_CHATF_ITALIC?TRUE:FALSE);
  1081.       Style.Underline = (buf[i]&TCP_CHATF_UNDERLINE?TRUE:FALSE);
  1082.       set(socks->RCObj->TE_ChatRemote,MUIA_TextEditor_StyleBold,Style.Bold);
  1083.       set(socks->RCObj->TE_ChatRemote,MUIA_TextEditor_StyleItalic,Style.Italic);
  1084.       set(socks->RCObj->TE_ChatRemote,MUIA_TextEditor_StyleUnderline,Style.Underline);
  1085.       i += 3;
  1086.       break;
  1087.     }
  1088.     case 0x04: //Activate window
  1089.     case 0x03: //De-Activate window
  1090.       break;
  1091.     case 0x0b: //End Chat Mode
  1092.       EndChat(socks->RCObj->GP_RemoteObj);
  1093.       return;
  1094.     case 0x10: //Change Font Name
  1095.       i++;
  1096.       revmemcpy((char *)&flen,buf+i,2); i += 2;
  1097.       font = buf+i; i += (flen+1);
  1098.       break;
  1099.     case 0x08: //Backspace
  1100.       DoMethod(socks->RCObj->TE_ChatRemote,MUIM_TextEditor_ARexxCmd,"BACKSPACE");
  1101.       break;
  1102.     case 0x0d: //Return
  1103.       key[0] = '\n';
  1104.       DoMethod(socks->RCObj->TE_ChatRemote,MUIM_TextEditor_InsertText,key,MUIV_TextEditor_InsertText_Bottom);
  1105.       break;
  1106.     default:   //All remaining text
  1107.       key[0] = buf[i];
  1108.       if ((UBYTE)key[0] >= (UBYTE)' ') {
  1109.         text[0] = '\0';
  1110.         get(socks->RCObj->TE_ChatRemote,MUIA_TextEditor_StyleBold,&bold);
  1111.         get(socks->RCObj->TE_ChatRemote,MUIA_TextEditor_StyleItalic,&italic);
  1112.         get(socks->RCObj->TE_ChatRemote,MUIA_TextEditor_StyleUnderline,&underline);
  1113.         get(socks->RCObj->TE_ChatRemote,MUIA_TextEditor_Pen,&pen);
  1114.         if (bold) strcat(text,"\33b");
  1115.         if (italic) strcat(text,"\33i");
  1116.         if (underline) strcat(text,"\33u");
  1117.         sprintf(text,"%s\33p[%ld]%s\33n",text,pen,key);
  1118.         DoMethod(socks->RCObj->TE_ChatRemote,MUIM_TextEditor_InsertText,text,MUIV_TextEditor_InsertText_Bottom);
  1119.       }
  1120.       break;
  1121.   }
  1122. }
  1123.  
  1124. socks->Timehack = time(NULL);
  1125.  
  1126. return;
  1127.  
  1128. }
  1129.  
  1130.  
  1131. void __asm EndChat(REG(a2) APTR obj)
  1132.  
  1133. {
  1134.  
  1135. int i;
  1136.  
  1137. ULONG winuin, total, sess_count;
  1138.  
  1139. struct ChatSession *session;
  1140. struct Contact *user;
  1141. struct RemoteChatObj *RCObj;
  1142. struct Sockets *socks, *primesocks;
  1143.  
  1144. HandleError(DBG_TCP_DBUG,"EndChat()");
  1145.  
  1146. get(obj,MUIA_UserData,&winuin);
  1147.  
  1148. if (!(user = GetContact(winuin))) return;
  1149.  
  1150. if (!(socks = GetSocketFmContact(user,SOCK_CHAT))) return;
  1151.  
  1152. if (socks->Closing) return;
  1153.  
  1154. if (!(primesocks = GetSocketFmPort(socks->ConnectPort))) {
  1155.   DelSockets(socks->Socket);
  1156.   return;
  1157. }
  1158.  
  1159. if (!socks->RCObj) {
  1160.   HandleError(DBG_TCP_DBUG,"Got an empty socks->RCObj");
  1161.   DelSockets(socks->Socket);
  1162.   return;
  1163. }
  1164.  
  1165. RCObj = socks->RCObj;
  1166.  
  1167. socks->RCObj = NULL;
  1168.  
  1169. DelSockets(socks->Socket);
  1170.  
  1171. user->ChatListen = 0;
  1172.  
  1173. SaveChatText(user,primesocks->CWin,RCObj);
  1174.  
  1175. if (RCObj) {
  1176.   DoMethod(primesocks->CWin->GP_ChatGroups,MUIM_Group_InitChange);
  1177.   DoMethod(primesocks->CWin->GP_ChatGroups,OM_REMMEMBER,RCObj->GP_RemoteObj);
  1178.   MUI_DisposeObject(RCObj->GP_RemoteObj);
  1179.   FreeVec(RCObj);
  1180.   RCObj = NULL;
  1181.   DoMethod(primesocks->CWin->GP_ChatGroups,MUIM_Group_ExitChange);
  1182. }
  1183.  
  1184. sess_count = CountChatPorts(primesocks);
  1185.  
  1186. if (sess_count == 0) {
  1187.   set(primesocks->CWin->WI_ChatWin,MUIA_Window_Open,FALSE);
  1188.   DoMethod(app->App,OM_REMMEMBER,primesocks->CWin->WI_ChatWin);
  1189.   MUI_DisposeObject(primesocks->CWin->WI_ChatWin);
  1190.   FreeVec(primesocks->CWin);
  1191.   primesocks->CWin = NULL;
  1192.   get(app->LV_Sessions,MUIA_NList_Entries,&total);
  1193.   if (total > 0) {
  1194.     for(i = 0; i < total; i++) {
  1195.       DoMethod(app->LV_Sessions,MUIM_NList_GetEntry,i,&session);
  1196.       if (session) {
  1197.         if (session->ChatListen == primesocks->Port) {
  1198.           DoMethod(app->LV_Sessions,MUIM_NList_Remove,i);
  1199.           break;
  1200.         }
  1201.       }
  1202.     }
  1203.   }
  1204.   DelSockets(primesocks->Socket);
  1205. }
  1206. else UpdateChatSession(user,primesocks);
  1207.  
  1208. return;
  1209.  
  1210. }
  1211.  
  1212.  
  1213. void __asm ChatWinState(REG(a2) APTR obj)
  1214.  
  1215. {
  1216.  
  1217. BOOL *active;
  1218.  
  1219. char key[2];
  1220.  
  1221. ULONG uin;
  1222.  
  1223. struct Contact *user;
  1224. struct Sockets *primesocks;
  1225.  
  1226. get(obj,MUIA_UserData,&uin);
  1227.  
  1228. if (!(user = GetContact(uin))) return;
  1229.  
  1230. if (!(primesocks = GetSocketFmPort(user->ChatListen))) return;
  1231.  
  1232. key[1] = '\0';
  1233.  
  1234. get(primesocks->CWin->WI_ChatWin,MUIA_Window_Activate,&active);
  1235.  
  1236. if (active) key[0] = '\x03';
  1237. else key[0] = '\x04';
  1238.  
  1239. SendText(primesocks->Port,key,1);
  1240.  
  1241. return;
  1242.  
  1243. }
  1244.  
  1245.  
  1246. void UpdateChatSession(struct Contact *user, struct Sockets *primesocks)
  1247.  
  1248. {
  1249.  
  1250. BOOL flag = FALSE;
  1251.  
  1252. char *nick;
  1253.  
  1254. int i;
  1255.  
  1256. ULONG total;
  1257.  
  1258. struct ChatSession *session, Sess;
  1259.  
  1260. get(app->STR_Nick,MUIA_String_Contents,&nick);
  1261.  
  1262. strcpy(primesocks->CWin->Title,GetSessionNicks(primesocks));
  1263.  
  1264. set(primesocks->CWin->WI_ChatWin,MUIA_Window_Title,primesocks->CWin->Title);
  1265.  
  1266. get(app->LV_Sessions,MUIA_NList_Entries,&total);
  1267.  
  1268. if (total > 0) {
  1269.   for(i = 0; i < total; i++) {
  1270.     DoMethod(app->LV_Sessions,MUIM_NList_GetEntry,i,&session);
  1271.     if (session) {
  1272.       if (session->ChatListen == primesocks->Port) {
  1273.         strcpy(session->Session,primesocks->CWin->Title);
  1274.         flag = TRUE;
  1275.         break;
  1276.       }
  1277.     }
  1278.   }
  1279. }
  1280.  
  1281. if (!flag) {
  1282.   Sess.ChatListen = primesocks->Port;
  1283.   strcpy(Sess.Session,primesocks->CWin->Title);
  1284.   DoMethod(app->LV_Sessions,MUIM_NList_InsertSingle,&Sess,MUIV_NList_Insert_Sorted);
  1285. }
  1286.  
  1287. return;
  1288.  
  1289. }
  1290.  
  1291.  
  1292. struct ChatSession *GetChatSessionPort(UWORD port)
  1293.  
  1294. {
  1295.  
  1296. int i;
  1297.  
  1298. ULONG total;
  1299.  
  1300. struct ChatSession *session;
  1301.  
  1302. get(app->LV_Sessions,MUIA_NList_Entries,&total);
  1303.  
  1304. if (total > 0) {
  1305.   for(i = 0; i < total; i++) {
  1306.     DoMethod(app->LV_Sessions,MUIM_NList_GetEntry,i,&session);
  1307.     if (session) if (session->ChatListen == port) return(session);
  1308.   }
  1309. }
  1310.  
  1311. return(NULL);
  1312.  
  1313. }
  1314.  
  1315.  
  1316. ULONG CountChatPorts(struct Sockets *primesocks)
  1317.  
  1318. {
  1319.  
  1320. int i;
  1321.  
  1322. ULONG total, count = 0;
  1323.  
  1324. struct Sockets *socks;
  1325.  
  1326. HandleError(DBG_TCP_DBUG,"CountChatPorts(%d)",primesocks->Port);
  1327.  
  1328. get(app->LV_SockList,MUIA_NList_Entries,&total);
  1329.  
  1330. for(i = 0; i < total; i++) {
  1331.   DoMethod(app->LV_SockList,MUIM_NList_GetEntry,i,&socks);
  1332.   if (socks) {
  1333.     if (socks->ConnectPort == primesocks->Port && socks != primesocks) {
  1334.       count++;
  1335.       HandleError(DBG_TCP_DBUG,"Socket %d has ConnectPort %d",socks->Socket,socks->ConnectPort);
  1336.     }
  1337.   }
  1338. }
  1339.  
  1340. HandleError(DBG_TCP_DBUG,"CountChatPorts() = %ld",count);
  1341.  
  1342. return(count);
  1343.  
  1344. }
  1345.  
  1346.  
  1347. void SaveChatText(struct Contact *user, struct ChatWin *CWin, struct RemoteChatObj *RCObj)
  1348.  
  1349. {
  1350.  
  1351. char uinlog[MAXNAMLEN], *rchat, *lchat;
  1352.  
  1353. ULONG uin;
  1354.  
  1355. struct AsyncFile *logfh;
  1356.  
  1357. rchat = (char *)DoMethod(RCObj->TE_ChatRemote,MUIM_TextEditor_ExportText);
  1358. lchat = (char *)DoMethod(CWin->TE_ChatLocal,MUIM_TextEditor_ExportText);
  1359.  
  1360. if (!rchat) rchat = LINE;
  1361. if (!lchat) lchat = LINE;
  1362.  
  1363. if (!strlen(rchat) && !strlen(lchat)) return;
  1364.  
  1365. /*
  1366.  
  1367.   MUI hits enforcer/cyberguard/muforce when the next line is executed.  I see this as an MUI bug, not STRICQ.
  1368.  
  1369. */
  1370.  
  1371. if (MUI_Request(app->App,CWin->WI_ChatWin,0,NULL,"Save|Discard","Save Chat Contents?")) {
  1372.   get(app->STR_ICQUIN,MUIA_String_Integer,&uin);
  1373.   sprintf(uinlog,"%sUsers/%ld/Logs/%ld",currentdir,uin,user->UIN);
  1374.   if (logfh = OpenAsync(uinlog,MODE_APPEND,AsyncBuf)) {
  1375. //  for(c = rchat; *c; c++) if (*c == '\n') *c = ' ';
  1376.     WriteLineAsync(logfh,"Chat R: ");
  1377.     WriteLineAsync(logfh,rchat);
  1378.     WriteLineAsync(logfh,"\n\n");
  1379.     set(RCObj->TE_ChatRemote,MUIA_TextEditor_Contents,NULL);
  1380.     if (strlen(rchat)) FreeVec(rchat);
  1381. //  for(c = lchat; *c; c++) if (*c == '\n') *c = ' ';
  1382.     WriteLineAsync(logfh,"Chat S: ");
  1383.     WriteLineAsync(logfh,lchat);
  1384.     WriteLineAsync(logfh,"\n\n");
  1385.     set(CWin->TE_ChatLocal,MUIA_TextEditor_Contents,NULL);
  1386.     if (strlen(lchat)) FreeVec(lchat);
  1387.     CloseAsync(logfh);
  1388.     SetComment(uinlog,GetNick(user->UIN));
  1389.   }
  1390. }
  1391.  
  1392. return;
  1393.  
  1394. }
  1395.  
  1396.  
  1397. void __asm EndAllChat(REG(a2) APTR obj)
  1398.  
  1399. {
  1400.  
  1401. int i;
  1402.  
  1403. ULONG winuin, total;
  1404.  
  1405. struct ChatSession *session;
  1406. struct Contact *user;
  1407. struct Sockets *socks, *primesocks;
  1408.  
  1409. get(obj,MUIA_UserData,&winuin);
  1410.  
  1411. if (!(user = GetContact(winuin))) return;
  1412.  
  1413. if (!(primesocks = GetSocketFmPort(user->ChatListen))) return;
  1414.  
  1415. get(app->LV_SockList,MUIA_NList_Entries,&total);
  1416.  
  1417. for(i = 0; i < total; i++) {
  1418.   DoMethod(app->LV_SockList,MUIM_NList_GetEntry,i,&socks);
  1419.   if (socks) if (socks->ConnectPort == primesocks->Port && socks != primesocks) socks->Closing = TRUE;
  1420. }
  1421.  
  1422. if (!MUI_Request(app->App,primesocks->CWin->WI_ChatWin,0,NULL,"Yes|No","Exit Chat.  Are you sure?")) {
  1423.   for(i = 0; i < total; i++) {
  1424.     DoMethod(app->LV_SockList,MUIM_NList_GetEntry,i,&socks);
  1425.     if (socks) if (socks->ConnectPort == primesocks->Port && socks != primesocks) socks->Closing = FALSE;
  1426.   }
  1427.   return;
  1428. }
  1429.  
  1430. for(i = 0; i < total; i++) {
  1431.   DoMethod(app->LV_SockList,MUIM_NList_GetEntry,i,&socks);
  1432.   if (socks) {
  1433.     if (socks->ConnectPort == primesocks->Port && socks != primesocks) {
  1434.       user = GetContact(socks->UIN);
  1435.       user->ChatListen = 0;
  1436.       HandleError(DBG_TCP_DBUG,"Shutting down %s's chat socket %d",user->Nick,socks->Socket);
  1437.       if (socks->RCObj) {
  1438.         SaveChatText(user,primesocks->CWin,socks->RCObj);
  1439.         DoMethod(primesocks->CWin->GP_ChatGroups,MUIM_Group_InitChange);
  1440.         DoMethod(primesocks->CWin->GP_ChatGroups,OM_REMMEMBER,socks->RCObj->GP_RemoteObj);
  1441.         MUI_DisposeObject(socks->RCObj->GP_RemoteObj);
  1442.         FreeVec(socks->RCObj);
  1443.         socks->RCObj = NULL;
  1444.         DoMethod(primesocks->CWin->GP_ChatGroups,MUIM_Group_ExitChange);
  1445.       }
  1446.       send(socks->Socket,"\x0B",1,0);
  1447.       DelSockets(socks->Socket);
  1448.     }
  1449.   }
  1450. }
  1451.  
  1452. set(primesocks->CWin->WI_ChatWin,MUIA_Window_Open,FALSE);
  1453.  
  1454. DoMethod(app->App,OM_REMMEMBER,primesocks->CWin->WI_ChatWin);
  1455.  
  1456. MUI_DisposeObject(primesocks->CWin->WI_ChatWin);
  1457.  
  1458. FreeVec(primesocks->CWin);
  1459.  
  1460. primesocks->CWin = NULL;
  1461.  
  1462. get(app->LV_Sessions,MUIA_NList_Entries,&total);
  1463.  
  1464. if (total > 0) {
  1465.   for(i = 0; i < total; i++) {
  1466.     DoMethod(app->LV_Sessions,MUIM_NList_GetEntry,i,&session);
  1467.     if (session) {
  1468.       if (session->ChatListen == primesocks->Port) {
  1469.         DoMethod(app->LV_Sessions,MUIM_NList_Remove,i);
  1470.         break;
  1471.       }
  1472.     }
  1473.   }
  1474. }
  1475.  
  1476. DelSockets(primesocks->Socket);
  1477.  
  1478. return;
  1479.  
  1480. }
  1481.  
  1482.  
  1483. void __asm SetBIU(REG(a2) APTR obj)
  1484.  
  1485. {
  1486.  
  1487. BOOL *bold, *italic, *underline;
  1488.  
  1489. char buf[16];
  1490.  
  1491. ULONG uin;
  1492.  
  1493. UWORD len;
  1494.  
  1495. struct Contact *user;
  1496. struct Sockets *primesocks;
  1497. struct TCP_ChatCmdStyle Style;
  1498.  
  1499. get(obj,MUIA_UserData,&uin);
  1500.  
  1501. user = GetContact(uin);
  1502.  
  1503. primesocks = GetSocketFmPort(user->ChatListen);
  1504.  
  1505. get(primesocks->CWin->TE_ChatLocal,MUIA_TextEditor_StyleBold,&bold);
  1506. get(primesocks->CWin->TE_ChatLocal,MUIA_TextEditor_StyleItalic,&italic);
  1507. get(primesocks->CWin->TE_ChatLocal,MUIA_TextEditor_StyleUnderline,&underline);
  1508.  
  1509. Style.Bold = (bold?TRUE:FALSE);
  1510. Style.Italic = (italic?TRUE:FALSE);
  1511. Style.Underline = (underline?TRUE:FALSE);
  1512.  
  1513. len = TCP_CreateChatCmd(TCP_CHAT_CMD_STYLE,&Style,buf);
  1514.  
  1515. SendText(primesocks->Port,buf,len);
  1516.  
  1517. return;
  1518.  
  1519. }
  1520.  
  1521.  
  1522. void SendText(UWORD port, char *text, UWORD len)
  1523.  
  1524. {
  1525.  
  1526. int i;
  1527.  
  1528. ULONG total;
  1529.  
  1530. struct Sockets *socks;
  1531.  
  1532. get(app->LV_SockList,MUIA_NList_Entries,&total);
  1533.  
  1534. for(i = 0; i < total; i++) {
  1535.   DoMethod(app->LV_SockList,MUIM_NList_GetEntry,i,&socks);
  1536.   if (socks) {
  1537.     if (socks->ConnectPort == port && socks->Dir != TCP_DIR_LISTEN) {
  1538.       send(socks->Socket,text,len,0);
  1539.       socks->Timehack = time(NULL);
  1540.     }
  1541.   }
  1542. }
  1543.  
  1544. return;
  1545.  
  1546. }
  1547.  
  1548.  
  1549. void __asm SetLocalFColor(REG(a2) APTR obj)
  1550.  
  1551. {
  1552.  
  1553. char buf[16];
  1554.  
  1555. LONG entry;
  1556.  
  1557. ULONG uin;
  1558.  
  1559. UWORD len;
  1560.  
  1561. struct Contact *user;
  1562. struct Sockets *primesocks;
  1563. struct TCP_ChatColor Color;
  1564.  
  1565. get(obj,MUIA_NList_EntryClick,&entry);
  1566.  
  1567. if (entry < 0 || entry >= NUM_CHAT_COLORS) return;
  1568.  
  1569. get(obj,MUIA_NList_PrivateData,&uin);
  1570.  
  1571. user = GetContact(uin);
  1572.  
  1573. primesocks = GetSocketFmPort(user->ChatListen);
  1574.  
  1575. set(primesocks->CWin->TE_ChatLocal,MUIA_TextEditor_Pen,entry+1);
  1576.  
  1577. Color.Red = ChatColors[entry][0];
  1578. Color.Green = ChatColors[entry][1];
  1579. Color.Blue = ChatColors[entry][2];
  1580.  
  1581. len = TCP_CreateChatCmd(TCP_CHAT_CMD_FCOLOR,&Color,buf);
  1582.  
  1583. SendText(primesocks->Port,buf,len);
  1584.  
  1585. return;
  1586.  
  1587. }
  1588.