2 * Copyright (C) Volition, Inc. 2005. All rights reserved.
4 * All source code herein is the property of Volition, Inc. You may not sell
5 * or otherwise commercially exploit the source or things you created based on the
13 #include <sys/types.h>
14 #include <sys/socket.h>
15 #include <sys/ioctl.h>
16 #include <netinet/in.h>
17 #include <sys/select.h>
19 #include <arpa/inet.h>
22 #define WSAGetLastError() (errno)
25 typedef int socklen_t;
31 #define MAXCHATBUFFER 500
33 static SOCKET Chatsock;
34 static SOCKADDR_IN Chataddr;
35 static int Socket_connecting = 0;
36 static char Nick_name[33];
37 static char Original_nick_name[33];
38 static int Nick_variety = 0;
39 static char szChat_channel[33] = "";
40 static char Input_chat_buffer[MAXCHATBUFFER] = "";
41 static char Chat_tracker_id[33];
42 static char Getting_user_channel_info_for[33] = "";
43 static char Getting_user_tracker_info_for[33] = "";
44 static int Getting_user_channel_error = 0;
45 static int Getting_user_tracker_error = 0;
46 static char User_req_tracker_id[100] = ""; //These are oversized for saftey
47 static char User_req_channel[100] = "";
48 static char *User_list = NULL;
49 static char *Chan_list = NULL;
50 static int Socket_connected = 0;
51 static int Chat_server_connected = 0;
52 static int Joining_channel = 0;
53 static int Joined_channel = 0;
54 static int GettingChannelList = 0;
55 static int GettingUserTID = 0;
56 static int GettingUserChannel = 0;
58 static Chat_user *Firstuser,*Curruser;
59 static Chat_command *Firstcommand,*Currcommand;
60 static Chat_channel *Firstchannel,*Currchannel;
64 Socket_connecting = 0;
66 SDL_zero(Original_nick_name);
68 SDL_zero(szChat_channel);
69 SDL_zero(Input_chat_buffer);
70 SDL_zero(Chat_tracker_id);
71 SDL_zero(Getting_user_channel_info_for);
72 SDL_zero(Getting_user_tracker_info_for);
73 Getting_user_channel_error = 0;
74 Getting_user_tracker_error = 0;
75 SDL_zero(User_req_tracker_id);
76 SDL_zero(User_req_channel);
80 Chat_server_connected = 0;
83 GettingChannelList = 0;
85 GettingUserChannel = 0;
91 //-2 Already connected
92 //-1 Failed to connect
95 // Call it once with the server IP address, and it will return immediately
96 // with 0. Keep calling it until it returns something other than 0
97 // note: the nickname may be changed if someone with that name already
98 // exists (Scourge1 for instance)
99 int ConnectToChatServer(char *serveraddr,char *nickname,char *trackerid)
102 char chat_server[50];
104 unsigned long argp = 1;
105 char signon_str[100];
107 //if(Socket_connected && ) return -2;
109 if(!Socket_connecting)
113 SDL_strlcpy(Nick_name, nickname, sizeof(Nick_name));
114 SDL_strlcpy(Original_nick_name, nickname, sizeof(Original_nick_name));
115 SDL_strlcpy(Chat_tracker_id, trackerid, sizeof(Chat_tracker_id));
119 Chat_server_connected = 0;
120 FlushChatCommandQueue();
122 p = strchr(serveraddr,':');
126 //AfxMessageBox("Invalid chat server, must be host.com:port (ie. irc.dal.net:6667)");
129 SDL_strlcpy(chat_server, serveraddr, sizeof(chat_server));
130 chat_server[p-serveraddr]='\0';
131 chat_port = (short)atoi(p+1);
134 //AfxMessageBox("Invalid chat port, must be host.com:port (ie. irc.dal.net:6667)");
138 Chatsock = socket(AF_INET,SOCK_STREAM,0);
139 if(INVALID_SOCKET == Chatsock)
141 //AfxMessageBox("Unable to open socket!");
145 memset( &Chataddr, 0, sizeof(SOCKADDR_IN) );
146 Chataddr.sin_family = AF_INET;
147 Chataddr.sin_addr.s_addr = INADDR_ANY;
148 Chataddr.sin_port = 0;
150 if (SOCKET_ERROR==bind(Chatsock, (SOCKADDR*)&Chataddr, sizeof (sockaddr)))
152 //AfxMessageBox("Unable to bind socket!");
155 ioctlsocket(Chatsock,FIONBIO,&argp);
157 // first try and resolve by name
158 iaddr = inet_addr( chat_server );
159 if ( iaddr == INADDR_NONE ) {
161 he = gethostbyname(chat_server);
166 //AfxMessageBox("Unable to gethostbyname.\n");
168 // try and resolve by address
169 unsigned int n_order = inet_addr(chat_server);
170 he = gethostbyaddr((char*)&n_order,4,PF_INET);
177 memcpy(&iaddr, he->h_addr_list[0],4);
180 memcpy(&Chataddr.sin_addr.s_addr, &iaddr,4); //&iaddr, 4);
183 // Chataddr.sin_addr.s_addr = inet_addr(chat_server);
185 Chataddr.sin_port = htons( chat_port );
187 if(SOCKET_ERROR == connect(Chatsock,(SOCKADDR *)&Chataddr,sizeof(SOCKADDR_IN)))
189 if(WSAEWOULDBLOCK == WSAGetLastError())
191 Socket_connecting = 1;
197 //This should never happen, connect should always return WSAEWOULDBLOCK
198 Socket_connecting = 1;
199 Socket_connected = 1;
205 if(Chat_server_connected)
210 if(!Socket_connected)
212 //Do a few select to check for an error, or to see if we are writeable (connected)
213 fd_set write_fds,error_fds;
220 FD_SET(Chatsock,&write_fds);
221 //Writable -- that means it's connected
222 if(select(0,NULL,&write_fds,NULL,&timeout))
224 Socket_connected = 1;
225 SDL_snprintf(signon_str, sizeof(signon_str), NOX("/USER %s %s %s :%s"), NOX("user"), NOX("user"), NOX("user"), Chat_tracker_id);
226 SendChatString(signon_str,1);
227 SDL_snprintf(signon_str, sizeof(signon_str), NOX("/NICK %s"), Nick_name);
228 SendChatString(signon_str,1);
230 //Now we are waiting for Chat_server_connected
233 FD_SET(Chatsock,&error_fds);
234 //error -- that means it's not going to connect
235 if(select(0,NULL,NULL,&error_fds,&timeout))
246 // Call it to close the connection. It returns immediately
247 void DisconnectFromChatServer()
249 if(!Socket_connected) return;
250 SendChatString(NOX("/QUIT"),1);
251 shutdown(Chatsock,2);
252 closesocket(Chatsock);
253 Socket_connecting = 0;
254 Socket_connected = 0;
255 Input_chat_buffer[0] = '\0';
267 Chat_server_connected = 0;
270 RemoveAllChatUsers();
271 FlushChatCommandQueue();
275 // returns NULL if no line is there to print, otherwise returns a string to
276 // print (all preformatted of course)
280 if(!Socket_connected) return NULL;
282 //ChatGetString will do the formatting
283 return ChatGetString();
287 // Send a string to be sent as chat, or scanned for messages (/msg <user>
289 const char * SendChatString(const char *line,int raw)
293 if(!Socket_connected) return NULL;
298 //Start off by getting the command
299 SDL_strlcpy(szCmd, GetWordNum(0,line+1), sizeof(szCmd));
300 if(SDL_strcasecmp(szCmd,NOX("msg"))==0)
302 SDL_strlcpy(szTarget, GetWordNum(1,line+1), sizeof(szTarget));
303 SDL_snprintf(szCmd, sizeof(szCmd), NOX("PRIVMSG %s :%s\n\r"), szTarget, line+strlen(NOX("/msg "))+strlen(szTarget)+1);
304 send(Chatsock,szCmd,strlen(szCmd),0);
305 szCmd[strlen(szCmd)-2]='\0';
306 return ParseIRCMessage(szCmd,MSG_LOCAL);
309 if(SDL_strcasecmp(szCmd,NOX("me"))==0)
311 SDL_snprintf(szCmd, sizeof(szCmd), NOX("PRIVMSG %s :\001ACTION %s\001\n\r"), szChat_channel, line+strlen(NOX("/me ")));
312 send(Chatsock,szCmd,strlen(szCmd),0);
313 szCmd[strlen(szCmd)-2]='\0';
314 return ParseIRCMessage(szCmd,MSG_LOCAL);
317 if(SDL_strcasecmp(szCmd,NOX("xyz"))==0)
319 //Special command to send raw irc commands
320 SDL_snprintf(szCmd, sizeof(szCmd), "%s\n\r", line+strlen(NOX("/xyz ")));
321 send(Chatsock,szCmd,strlen(szCmd),0);
324 if(SDL_strcasecmp(szCmd,NOX("list"))==0)
326 SDL_snprintf(szCmd, sizeof(szCmd), "%s\n\r", line+1);
327 send(Chatsock,szCmd,strlen(szCmd),0);
332 SDL_snprintf(szCmd, sizeof(szCmd), "%s\n\r", line+1);
333 send(Chatsock,szCmd,strlen(szCmd),0);
336 return XSTR("Unrecognized command",634);
341 if(szChat_channel[0])
345 sndstr.Format("PRIVMSG %s :%s\n\r",szChat_channel,line);
346 send(Chatsock,LPCSTR(sndstr),sndstr.GetLength(),0);
347 sndstr = sndstr.Left(sndstr.GetLength()-2);
348 return ParseIRCMessage((char *)LPCSTR(sndstr),MSG_LOCAL);
351 SDL_snprintf(szCmd, sizeof(szCmd), NOX("PRIVMSG %s :%s\n\r"), szChat_channel, line);
352 send(Chatsock,szCmd,strlen(szCmd),0);
353 if(strlen(szCmd) >= 2){
354 szCmd[strlen(szCmd)-2] = '\0';
355 return ParseIRCMessage(szCmd,MSG_LOCAL);
366 // Returns a structure which contains a command and possible some data (like
367 // a user joining or leaving) if one is waiting
368 // This tells you if you need to add a user from the userlist, remove a user,
369 // etc. Also for status messages, like if you get knocked
370 // off the server for some reason.
371 Chat_command *GetChatCommand()
373 if(!Socket_connected) return NULL;
374 return GetChatCommandFromQueue();
377 // This function returns a list of users in the current channel, in one
378 // string, separated by spaces, terminated by a null
379 // (Spaces aren't allowed as part of a nickname)
380 char *GetChatUserList()
382 int iuser_list_length = 0;;
388 if(!Socket_connected) return NULL;
390 Curruser = Firstuser;
393 iuser_list_length += strlen(Curruser->nick_name)+1;
394 Curruser = Curruser->next;
396 Curruser = Firstuser;
397 User_list = (char *)malloc(iuser_list_length+1);
401 strcat(User_list,Curruser->nick_name);
402 strcat(User_list," ");
403 Curruser = Curruser->next;
409 // Call this to set/join a channel. Since we can't be sure that we will be
410 // able to join that channel, check it for completion
411 // You can't be in more than one channel at a time with this API, so you
412 // leave the current channel before trying to join
413 // a new one. Because of this if the join fails, make sure you try to join
414 // another channel, or the user wont be able to chat
417 // 1 successfully joined
418 int SetNewChatChannel(char *channel)
421 if(!Socket_connected) return -1;
422 if(Joining_channel==1)
424 if(Joined_channel==1)
430 else if(Joined_channel==-1)
432 //Error -- we got a message that the channel was invite only, or we were banned or something
434 SDL_zero(szChat_channel);
440 if(szChat_channel[0])
442 SDL_snprintf(partstr, sizeof(partstr), NOX("/PART %s"), szChat_channel);
443 SendChatString(partstr,1);
445 SDL_strlcpy(szChat_channel, channel, sizeof(szChat_channel));
446 SDL_snprintf(partstr, sizeof(partstr), NOX("/JOIN %s"), szChat_channel);
447 SendChatString(partstr,1);
456 char *ChatGetString(void)
463 static char return_string[MAXCHATBUFFER];
469 FD_SET(Chatsock,&read_fds);
470 //Writable -- that means it's connected
471 while(select(0,&read_fds,NULL,NULL,&timeout))
473 bytesread = recv(Chatsock,ch,1,0);
478 if((ch[0] == 0x0a)||(ch[0]==0x0d))
480 if(Input_chat_buffer[0]=='\0')
482 //Blank line, ignore it
485 SDL_strlcpy(return_string, Input_chat_buffer, sizeof(return_string));
486 Input_chat_buffer[0] = '\0';
488 p = ParseIRCMessage(return_string,MSG_REMOTE);
492 SDL_assert(strlen(Input_chat_buffer) < MAXCHATBUFFER-1);
493 SDL_strlcat(Input_chat_buffer, ch, sizeof(Input_chat_buffer));
497 //Select said we had read data, but 0 bytes read means disconnected
498 AddChatCommandToQueue(CC_DISCONNECTED,NULL,0);
507 const char * GetWordNum(int num, const char * l_String)
509 static char strreturn[600];
510 static char ptokstr[600];
511 char seps[10] = NOX(" \n\r\t");
512 char *token,*strstart;
516 SDL_strlcpy(ptokstr, l_String, sizeof(ptokstr));
518 token=strtok(ptokstr,seps);
520 for(int i=0;i!=num;i++)
522 token=strtok(NULL,seps);
526 SDL_strlcpy(strreturn, token, sizeof(strreturn));
532 //check for the ':' char....
535 //Its not pretty, but it works, return the rest of the string
536 SDL_strlcpy(strreturn, l_String+((token-strstart)+1), sizeof(strreturn));
539 //return the appropriate response.
543 int AddChatUser(const char *nickname)
545 Curruser = Firstuser;
548 if(SDL_strcasecmp(nickname,Curruser->nick_name)==0) return 0;
549 Curruser = Curruser->next;
552 Curruser = Firstuser;
555 Firstuser = (Chat_user *)malloc(sizeof(Chat_user));
556 SDL_assert(Firstuser);
557 SDL_strlcpy(Firstuser->nick_name, nickname, sizeof(Firstuser->nick_name));
558 Firstuser->next = NULL;
559 AddChatCommandToQueue(CC_USER_JOINING,nickname,strlen(nickname)+1);
564 while(Curruser->next)
566 Curruser = Curruser->next;
568 Curruser->next = (Chat_user *)malloc(sizeof(Chat_user));
569 Curruser = Curruser->next;
570 SDL_assert(Curruser);
571 SDL_strlcpy(Curruser->nick_name, nickname, sizeof(Curruser->nick_name));
572 Curruser->next = NULL;
573 AddChatCommandToQueue(CC_USER_JOINING,nickname,strlen(nickname)+1);
579 int RemoveChatUser(char *nickname)
581 Chat_user *prv_user = NULL;
583 Curruser = Firstuser;
586 if(SDL_strcasecmp(nickname,Curruser->nick_name)==0)
590 prv_user->next = Curruser->next;
595 Firstuser = Curruser->next;
597 AddChatCommandToQueue(CC_USER_LEAVING,Curruser->nick_name,strlen(Curruser->nick_name)+1);
602 Curruser = Curruser->next;
608 void RemoveAllChatUsers(void)
610 Chat_user *tmp_user = NULL;
611 Curruser = Firstuser;
614 tmp_user = Curruser->next;
615 AddChatCommandToQueue(CC_USER_LEAVING,Curruser->nick_name,strlen(Curruser->nick_name)+1);
623 char * ParseIRCMessage(char *Line, int iMode)
625 char szRemLine[MAXLOCALSTRING] ="";
626 const char *pszTempStr;
627 char szPrefix[MAXLOCALSTRING] = "";
628 char szHackPrefix[MAXLOCALSTRING] = "";
629 char szTarget[MAXLOCALSTRING] = "";
630 char szNick[MAXLOCALSTRING] = "";
631 char szCmd[MAXLOCALSTRING] = "";
632 char szCTCPCmd[MAXLOCALSTRING] = "";
634 static char szResponse[MAXLOCALSTRING] = "";
637 int iPrefixLen = 0; // JAS: Get rid of optimized warning
639 if(strlen(Line)>=MAXLOCALSTRING)
644 if(iMode==MSG_REMOTE)
646 SDL_strlcpy(szRemLine, Line, sizeof(szRemLine));
647 //Start by getting the prefix
651 pszTempStr=GetWordNum(0,Line+1);
652 SDL_strlcpy(szPrefix, pszTempStr, sizeof(szPrefix));
653 SDL_strlcpy(szHackPrefix, pszTempStr, sizeof(szHackPrefix));
654 SDL_strlcpy(szRemLine, Line+1+strlen(szPrefix), sizeof(szRemLine));
657 pszTempStr=strtok(szHackPrefix,"!");
660 SDL_strlcpy(szNick, pszTempStr, sizeof(szNick));
664 SDL_strlcpy(szNick, szPrefix, sizeof(szNick));
666 //strcpy(NewMsg.Nickname,szNick);
667 iNickLen=strlen(szNick);
668 iPrefixLen=strlen(szPrefix);
670 else if(iMode==MSG_LOCAL)
672 SDL_strlcpy(szRemLine, Line, sizeof(szRemLine));
673 SDL_strlcpy(szNick, Nick_name, sizeof(szNick));
674 SDL_strlcpy(szPrefix, Nick_name, sizeof(szPrefix));
675 //strcpy(NewMsg.Nickname,szNick);
679 //Next is the command
680 pszTempStr=GetWordNum(0,szRemLine);
683 SDL_strlcpy(szCmd, pszTempStr, sizeof(szCmd));
687 //Shouldn't ever happen, but we can't be sure of what the host will send us.
691 //Move the szRemLine string up
692 SDL_strlcpy(szRemLine, Line+iPrefixLen+strlen(szCmd)+2, sizeof(szRemLine));
693 //Now parse the commands!
694 //printf("%s",szCmd);
695 if(SDL_strcasecmp(szCmd,NOX("PRIVMSG"))==0)
697 pszTempStr=GetWordNum(0,szRemLine);
698 SDL_strlcpy(szTarget, pszTempStr, sizeof(szTarget));
699 SDL_strlcpy(szRemLine, Line+iPrefixLen+strlen(szCmd)+strlen(szTarget)+4, sizeof(szRemLine));
700 if(szRemLine[0]==':')
702 SDL_strlcpy(szCTCPCmd, GetWordNum(0,szRemLine+1), sizeof(szCTCPCmd));
703 if(szCTCPCmd[strlen(szCTCPCmd)-1]==0x01) szCTCPCmd[strlen(szCTCPCmd)-1]=0x00;
708 SDL_strlcpy(szCTCPCmd, GetWordNum(0,szRemLine), sizeof(szCTCPCmd));
709 if(szCTCPCmd[strlen(szCTCPCmd)-1]==0x01) szCTCPCmd[strlen(szCTCPCmd)-1]=0x00;
711 if(szCTCPCmd[0]==0x01)
713 //Handle ctcp message
714 SDL_strlcpy(szRemLine, Line+iPrefixLen+strlen(szCmd)+strlen(szTarget)+strlen(szCTCPCmd)+6, sizeof(szRemLine));
715 szRemLine[strlen(szRemLine)-1]='\0';//null out the ending 0x01
716 if(SDL_strcasecmp(szCTCPCmd+1,NOX("ACTION"))==0)
719 SDL_snprintf(szResponse, sizeof(szResponse), "* %s %s", szNick, szRemLine);
724 SDL_strlcpy(szHackPrefix, Line+iPrefixLen+strlen(szCmd)+strlen(szTarget)+4, sizeof(szHackPrefix));
725 szRemLine[strlen(szRemLine)-1]='\0';
726 SDL_snprintf(szResponse, sizeof(szResponse), NOX("** CTCP %s %s %s"), szTarget, szCTCPCmd+1, szRemLine);
729 if(SDL_strcasecmp(szCTCPCmd+1,NOX("PING"))==0)
731 SDL_snprintf(szResponse, sizeof(szResponse), NOX("/NOTICE %s :\001PING %s\001"), szNick, szRemLine);//Don't need the trailing \001 because szremline has it.
732 SendChatString(szResponse,1);
735 if(SDL_strcasecmp(szCTCPCmd+1,NOX("VERSION"))==0)
737 //reply with a notice version & copyright
738 //sprintf(szTempLine,"NOTICE %s :\001VERSION Copyright(c)\001\n",szNick);
742 SDL_strlcpy(szRemLine, 1 + GetWordNum(0,Line+iPrefixLen+strlen(szCmd)+strlen(szTarget)+4), sizeof(szRemLine));
743 szRemLine[strlen(szRemLine)-1]='\0';
744 SDL_snprintf(szResponse, sizeof(szResponse), NOX("** CTCP Message from %s (%s)"), szNick, szRemLine);
748 //differentiate between channel and private
751 pszTempStr=GetWordNum(0,szRemLine);
752 SDL_snprintf(szResponse, sizeof(szResponse), "[%s] %s", szNick, pszTempStr);
757 if(iMode == MSG_LOCAL)
759 pszTempStr=GetWordNum(0,szRemLine);
760 SDL_snprintf(szResponse, sizeof(szResponse), NOX("Private Message to <%s>: %s"), szNick, pszTempStr);
764 pszTempStr=GetWordNum(0,szRemLine);
765 SDL_snprintf(szResponse, sizeof(szResponse), NOX("Private Message from <%s>: %s"), szNick, pszTempStr);
771 //don't handle any other messages locally.
777 if(SDL_strcasecmp(szCmd,NOX("NOTICE"))==0)
781 pszTempStr=GetWordNum(0,szRemLine);
782 SDL_strlcpy(szTarget, pszTempStr, sizeof(szTarget));
783 SDL_strlcpy(szRemLine, Line+iPrefixLen+strlen(szCmd)+strlen(szTarget)+4, sizeof(szRemLine));
784 if(szRemLine[0]==':')
786 SDL_strlcpy(szCTCPCmd, GetWordNum(0,szRemLine+1), sizeof(szCTCPCmd));
787 if(szCTCPCmd[strlen(szCTCPCmd)-1]==0x01) szCTCPCmd[strlen(szCTCPCmd)-1]=0x00;
792 SDL_strlcpy(szCTCPCmd, GetWordNum(0,szRemLine), sizeof(szCTCPCmd));
793 if(szCTCPCmd[strlen(szCTCPCmd)-1]==0x01) szCTCPCmd[strlen(szCTCPCmd)-1]=0x00;
795 if(szCTCPCmd[0]==0x01)
797 //Handle ctcp message
798 SDL_strlcpy(szRemLine, Line+iPrefixLen+strlen(szCmd)+strlen(szTarget)+strlen(szCTCPCmd)+6, sizeof(szRemLine));
799 szRemLine[strlen(szRemLine)-1]='\0';//null out the ending 0x01
800 if(SDL_strcasecmp(szCTCPCmd+1,NOX("PING"))==0)
802 //This is a ping response, figure out time and print
803 //sprintf(NewMsg.Message,"** Ping Response from %s: %ums",szNick,ulping);
808 SDL_strlcpy(szRemLine, 1 + GetWordNum(0,Line+iPrefixLen+strlen(szCmd)+strlen(szTarget)+4), sizeof(szRemLine));
809 szRemLine[strlen(szRemLine)-1]='\0';
810 SDL_snprintf(szResponse, sizeof(szResponse), XSTR("** CTCP Message from %s (%s)",635), szNick, szRemLine);
814 SDL_snprintf(szResponse, sizeof(szResponse), "%s", szRemLine);
817 if(SDL_strcasecmp(szCmd,NOX("JOIN"))==0)
820 if(SDL_strcasecmp(Nick_name,szNick)==0)
823 //if(strcmpi(szChat_channel,GetWordNum(0,szRemLine))==0)
826 if(SDL_strcasecmp(szChat_channel,NOX("#autoselect"))==0)
828 SDL_strlcpy(szChat_channel, GetWordNum(0,szRemLine), sizeof(szChat_channel));
829 AddChatCommandToQueue(CC_YOURCHANNEL,szChat_channel,strlen(szChat_channel)+1);
838 pszTempStr=GetWordNum(0,szRemLine);
839 SDL_strlcpy(szTarget, pszTempStr, sizeof(szTarget));
840 //strcpy(szRemLine,Line+iPrefixLen+strlen(szCmd)+strlen(szTarget)+3);
842 //strcpy(NewMsg.Channel,szTarget);
845 SDL_snprintf(szResponse, sizeof(szResponse), XSTR("** %s has joined %s",636), szNick, szTarget);
846 return NULL;//szResponse;
847 //Add them to the userlist too!
849 if(SDL_strcasecmp(szCmd,NOX("PART"))==0)
851 pszTempStr=GetWordNum(0,szRemLine);
852 SDL_strlcpy(szTarget, pszTempStr, sizeof(szTarget));
853 SDL_strlcpy(szRemLine, Line+iPrefixLen+strlen(szCmd)+strlen(szTarget)+3, sizeof(szRemLine));
855 if(SDL_strcasecmp(Nick_name,szNick)==0)
858 //szChat_channel[0]=NULL;
859 RemoveAllChatUsers();
862 RemoveChatUser(szNick);
864 //Remove them to the userlist too!
866 if(SDL_strcasecmp(szCmd,NOX("KICK"))==0)
868 pszTempStr=GetWordNum(0,szRemLine);
869 SDL_strlcpy(szTarget, pszTempStr, sizeof(szTarget));
870 pszTempStr=GetWordNum(1,szRemLine);
871 SDL_strlcpy(szHackPrefix, pszTempStr, sizeof(szHackPrefix));
872 pszTempStr=GetWordNum(2,szRemLine);
874 if(SDL_strcasecmp(Nick_name,GetWordNum(1,szRemLine))==0)
877 szChat_channel[0]='\0';
879 AddChatCommandToQueue(CC_KICKED,NULL,0);
880 RemoveAllChatUsers();
882 SDL_snprintf(szResponse, sizeof(szResponse), XSTR("*** %s has kicked %s from channel %s (%s)",637), szNick, szHackPrefix, szTarget, pszTempStr);
883 //Remove them to the userlist too!
884 RemoveChatUser(szNick);
888 if(SDL_strcasecmp(szCmd,NOX("NICK"))==0)
891 if(SDL_strcasecmp(Nick_name,szNick)==0)
894 SDL_strlcpy(Nick_name, GetWordNum(0,szRemLine), sizeof(Nick_name));
897 SDL_snprintf(nicks, sizeof(nicks), "%s %s", szNick, GetWordNum(0,szRemLine));
898 AddChatCommandToQueue(CC_NICKCHANGED,nicks,strlen(nicks)+1);
899 RemoveChatUser(szNick);
900 AddChatUser(GetWordNum(0,szRemLine));
901 SDL_snprintf(szResponse, sizeof(szResponse), XSTR("*** %s is now known as %s",638), szNick, GetWordNum(0,szRemLine));
904 if(SDL_strcasecmp(szCmd,NOX("PING"))==0)
906 //respond with pong (GetWordNum(0,szRemLine))
907 SDL_snprintf(szResponse, sizeof(szResponse), NOX("/PONG :%s"), GetWordNum(0,szRemLine));
908 SendChatString(szResponse,1);
911 if(SDL_strcasecmp(szCmd,NOX("MODE"))==0)
918 if(SDL_strcasecmp(szCmd,"401")==0)
920 //This is whois user info, we can get their tracker info from here. -5
921 char szWhoisUser[33];
922 SDL_strlcpy(szWhoisUser, GetWordNum(1,szRemLine), sizeof(szWhoisUser));
923 Getting_user_tracker_error = 1;
924 Getting_user_channel_error = 1;
926 SDL_snprintf(szResponse, sizeof(szResponse), XSTR("**Error: %s is not online!",639), szWhoisUser);
930 if(SDL_strcasecmp(szCmd,"311")==0)
932 char szWhoisUser[33];
933 SDL_strlcpy(szWhoisUser, GetWordNum(1,szRemLine), sizeof(szWhoisUser));
934 //This is whois user info, we can get their tracker info from here. -5
935 //if(strcmpi(Getting_user_tracker_info_for,szWhoisUser)==0)
937 SDL_strlcpy(User_req_tracker_id, GetWordNum(5,szRemLine), sizeof(User_req_tracker_id));
941 if(SDL_strcasecmp(szCmd,"319")==0)
943 char szWhoisUser[33];
944 SDL_strlcpy(szWhoisUser, GetWordNum(1,szRemLine), sizeof(szWhoisUser));
945 //This is whois channel info -- what channel they are on -2
946 //if(strcmpi(Getting_user_channel_info_for,szWhoisUser)==0)
948 SDL_strlcpy(User_req_channel, GetWordNum(2,szRemLine), sizeof(User_req_channel));
953 //End of whois and we didn't get a channel means they aren't in a channel.
954 if(SDL_strcasecmp(szCmd,"318")==0)
956 if(!*User_req_channel)
958 User_req_channel[0] = '*';
963 if(SDL_strcasecmp(szCmd,"321")==0)
965 //start of channel list
967 GettingChannelList = 1;
970 if(SDL_strcasecmp(szCmd,"322")==0)
973 if(GettingChannelList == 1)
975 char channel_list_name[33];
977 SDL_strlcpy(sztopic, GetWordNum(3,szRemLine), sizeof(sztopic));
978 SDL_strlcpy(channel_list_name, GetWordNum(1,szRemLine), sizeof(channel_list_name));
979 AddChannel(channel_list_name,(short)atoi(GetWordNum(2,szRemLine)),sztopic);
983 if(SDL_strcasecmp(szCmd,"323")==0)
985 //end of channel list
986 GettingChannelList = 2;
989 if(SDL_strcasecmp(szCmd,"324")==0)
995 if(SDL_strcasecmp(szCmd,"332")==0)
997 //Channel Topic, update status bar.
998 if(SDL_strcasecmp(szChat_channel,szTarget)==0)
1000 //strncpy(szChanTopic,GetWordNum(2,szRemLine),70);
1002 //sprintf(NewMsg.Message,"*** %s has changed the topic to: %s",szNick,GetWordNum(2,szRemLine));
1006 if(SDL_strcasecmp(szCmd,NOX("TOPIC"))==0)
1008 //Channel Topic, update status bar.
1009 if(SDL_strcasecmp(szChat_channel,szTarget)==0)
1011 //strncpy(szChanTopic,GetWordNum(1,szRemLine),70);
1013 //sprintf(NewMsg.Message,"*** %s has changed the topic to: %s",szNick,GetWordNum(1,szRemLine));
1016 if(SDL_strcasecmp(szCmd,NOX("QUIT"))==0)
1019 RemoveChatUser(szNick);
1022 if(SDL_strcasecmp(szCmd,"376")==0) //end of motd, trigger autojoin...
1024 if (!Chat_server_connected)
1026 Chat_server_connected=1;
1030 SDL_strlcpy(szResponse, PXO_CHAT_END_OF_MOTD_PREFIX, sizeof(szResponse));
1033 if((SDL_strcasecmp(szCmd,"377")==0)||
1034 (SDL_strcasecmp(szCmd,"372")==0)||
1035 (SDL_strcasecmp(szCmd,"372")==0)
1039 //Stip the message, and display it.
1040 pszTempStr=GetWordNum(3,Line);
1041 SDL_strlcpy(szResponse, PXO_CHAT_MOTD_PREFIX, sizeof(szResponse));
1042 SDL_strlcat(szResponse, pszTempStr, sizeof(szResponse));
1045 //Ignore these messages
1046 if(((SDL_strcasecmp(szCmd,"366")==0))||
1047 (SDL_strcasecmp(szCmd,"333")==0) || //Who set the topic
1048 (SDL_strcasecmp(szCmd,"329")==0)) //Time Channel created
1050 (SDL_strcasecmp(szCmd,"305")==0) ||
1051 (SDL_strcasecmp(szCmd,"306")==0) ||
1052 (SDL_strcasecmp(szCmd,"311")==0) || //WHOIS stuff
1053 (SDL_strcasecmp(szCmd,"312")==0) ||
1054 (SDL_strcasecmp(szCmd,"313")==0) ||
1055 (SDL_strcasecmp(szCmd,"317")==0) ||
1056 (SDL_strcasecmp(szCmd,"318")==0) ||
1057 (SDL_strcasecmp(szCmd,"319")==0) ||
1063 if(SDL_strcasecmp(szCmd,"353")==0)
1066 //Names in the channel.
1067 pszTempStr = GetWordNum(3,Line+iPrefixLen+strlen(szCmd)+2);
1068 SDL_strlcpy(szRemLine, pszTempStr, sizeof(szRemLine));
1069 pszTempStr = strtok(szRemLine," ");
1073 if(pszTempStr[0]=='@')
1075 AddChatUser(pszTempStr+1);
1077 else if(pszTempStr[0]=='+')
1079 AddChatUser(pszTempStr+1);
1083 AddChatUser(pszTempStr);
1085 pszTempStr=strtok(NULL," ");
1090 if((SDL_strcasecmp(szCmd,"001")==0)||
1091 (SDL_strcasecmp(szCmd,"002")==0)||
1092 (SDL_strcasecmp(szCmd,"003")==0)||
1093 (SDL_strcasecmp(szCmd,"004")==0)||
1094 (SDL_strcasecmp(szCmd,"251")==0)||
1095 (SDL_strcasecmp(szCmd,"254")==0)||
1096 (SDL_strcasecmp(szCmd,"255")==0)||
1097 (SDL_strcasecmp(szCmd,"265")==0)||
1098 (SDL_strcasecmp(szCmd,"375")==0)||
1099 (SDL_strcasecmp(szCmd,"372")==0)||
1100 (SDL_strcasecmp(szCmd,"375")==0)
1103 // Stip the message, and display it.
1104 // pszTempStr = GetWordNum(3, Line);
1105 // strcpy(szResponse, PXO_CHAT_MOTD_PREFIX);
1106 // strcat(szResponse, pszTempStr);
1108 // return szResponse;
1110 if(SDL_strcasecmp(szCmd,"432")==0)
1113 SDL_strlcpy(szResponse, XSTR("Your nickname contains invalid characters",640), sizeof(szResponse));
1114 AddChatCommandToQueue(CC_DISCONNECTED,NULL,0);
1117 if(SDL_strcasecmp(szCmd,"433")==0)
1121 SDL_snprintf(new_nick, sizeof(new_nick), "%s%d", Original_nick_name, Nick_variety);
1122 SDL_strlcpy(Nick_name, new_nick, sizeof(Nick_name));
1124 SDL_snprintf(szResponse, sizeof(szResponse), NOX("/NICK %s"), new_nick);
1125 SendChatString(szResponse,1);
1129 SDL_strlcpy(szResponse, Line, sizeof(szResponse));
1130 //return szResponse;
1136 void AddChatCommandToQueue(int command,const void *data,int len)
1138 Currcommand = Firstcommand;
1139 if(Firstcommand==NULL)
1141 Firstcommand = (Chat_command *)malloc(sizeof(Chat_command));
1142 SDL_assert(Firstcommand);
1143 Firstcommand->next = NULL;
1144 Currcommand = Firstcommand;
1148 while(Currcommand->next)
1150 Currcommand = Currcommand->next;
1152 Currcommand->next = (Chat_command *)malloc(sizeof(Chat_command));
1153 SDL_assert(Currcommand->next);
1154 Currcommand = Currcommand->next;
1156 Currcommand->command = (short)command;
1157 if(len&&data) memcpy(&Currcommand->data,data,len);
1158 Currcommand->next = NULL;
1162 Chat_command *GetChatCommandFromQueue(void)
1164 static Chat_command response_cmd;
1165 Chat_command *tmp_cmd;
1166 if(!Firstcommand) return NULL;
1167 Currcommand = Firstcommand;
1168 memcpy(&response_cmd,Currcommand,sizeof(Chat_command));
1169 tmp_cmd = Currcommand->next;
1171 Firstcommand = tmp_cmd;
1172 return &response_cmd;
1175 void FlushChatCommandQueue(void)
1177 Chat_command *tmp_cmd;
1178 Currcommand = Firstcommand;
1182 tmp_cmd = Currcommand->next;
1184 Currcommand = tmp_cmd;
1186 Firstcommand = NULL;
1190 void FlushChannelList(void)
1192 Chat_channel *tmp_chan;
1193 Currchannel = Firstchannel;
1197 tmp_chan = Currchannel->next;
1199 Currchannel = tmp_chan;
1201 Firstchannel = NULL;
1205 char *GetChannelList(void)
1207 int ichan_list_length = 0;
1208 char sznumusers[10];
1210 if(GettingChannelList != 2) return NULL;
1211 if(!Socket_connected) return NULL;
1220 Currchannel = Firstchannel;
1223 ichan_list_length += strlen(Currchannel->topic)+1+strlen(Currchannel->channel_name)+1+5;//1 for the space, and 4 for the number of users 0000-9999 + space
1224 Currchannel = Currchannel->next;
1226 Currchannel = Firstchannel;
1227 Chan_list = (char *)malloc(ichan_list_length+1);
1228 Chan_list[0] = '\0';
1231 strcat(Chan_list,"$");
1232 strcat(Chan_list,Currchannel->channel_name);
1233 strcat(Chan_list," ");
1234 sprintf(sznumusers,"%d ",Currchannel->users);
1235 strcat(Chan_list,sznumusers);
1236 strcat(Chan_list,Currchannel->topic);//fgets
1237 strcat(Chan_list," ");
1238 Currchannel = Currchannel->next;
1241 GettingChannelList = 0;
1245 void AddChannel(char *channel,unsigned short numusers,char *topic)
1247 Currchannel = Firstchannel;
1248 if(Firstchannel==NULL)
1250 Firstchannel = (Chat_channel *)malloc(sizeof(Chat_channel));
1251 SDL_assert(Firstchannel);
1252 SDL_strlcpy(Firstchannel->channel_name, channel, sizeof(Firstchannel->channel_name));
1253 SDL_strlcpy(Firstchannel->topic, topic, sizeof(Firstchannel->topic));
1254 Firstchannel->users = numusers;
1255 Firstchannel->next = NULL;
1256 Currchannel = Firstchannel;
1260 while(Currchannel->next)
1262 Currchannel = Currchannel->next;
1264 Currchannel->next = (Chat_channel *)malloc(sizeof(Chat_channel));
1265 SDL_assert(Currchannel->next);
1266 Currchannel = Currchannel->next;
1267 SDL_strlcpy(Currchannel->channel_name, channel, sizeof(Currchannel->channel_name));
1268 SDL_strlcpy(Currchannel->topic, topic, sizeof(Currchannel->topic));
1269 Currchannel->users = numusers;
1271 Currchannel->next = NULL;
1276 char *GetTrackerIdByUser(char *nickname)
1278 char szWhoisCmd[100];
1283 if(Getting_user_tracker_error)
1285 Getting_user_tracker_error = 0;
1290 if(*User_req_tracker_id)
1293 return User_req_tracker_id;
1298 SDL_strlcpy(Getting_user_tracker_info_for, nickname, sizeof(Getting_user_tracker_info_for));
1299 SDL_snprintf(szWhoisCmd, sizeof(szWhoisCmd), NOX("/WHOIS %s"), nickname);
1300 User_req_tracker_id[0] = '\0';
1301 SendChatString(szWhoisCmd,1);
1307 char *GetChannelByUser(char *nickname)
1309 char szWhoisCmd[100];
1311 if(GettingUserChannel)
1313 if(Getting_user_channel_error)
1315 Getting_user_channel_error = 0;
1316 GettingUserChannel = 0;
1319 if(*User_req_channel)
1321 GettingUserChannel = 0;
1322 return User_req_channel;
1327 SDL_strlcpy(Getting_user_channel_info_for, nickname, sizeof(Getting_user_channel_info_for));
1328 User_req_channel[0] = '\0';
1329 SDL_snprintf(szWhoisCmd, sizeof(szWhoisCmd), NOX("/WHOIS %s"), nickname);
1330 SendChatString(szWhoisCmd,1);
1331 GettingUserChannel = 1;