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>
23 #define WSAGetLastError() (errno)
26 typedef int socklen_t;
32 #define MAXCHATBUFFER 500
34 static SOCKET Chatsock;
35 static struct sockaddr_in Chataddr;
36 static int Socket_connecting = 0;
37 static char Nick_name[33];
38 static char Original_nick_name[33];
39 static int Nick_variety = 0;
40 static char szChat_channel[33] = "";
41 static char Input_chat_buffer[MAXCHATBUFFER] = "";
42 static char Chat_tracker_id[33];
43 static char Getting_user_channel_info_for[33] = "";
44 static char Getting_user_tracker_info_for[33] = "";
45 static int Getting_user_channel_error = 0;
46 static int Getting_user_tracker_error = 0;
47 static char User_req_tracker_id[100] = ""; //These are oversized for saftey
48 static char User_req_channel[100] = "";
49 static char *User_list = NULL;
50 static char *Chan_list = NULL;
51 static int Socket_connected = 0;
52 static int Chat_server_connected = 0;
53 static int Joining_channel = 0;
54 static int Joined_channel = 0;
55 static int GettingChannelList = 0;
56 static int GettingUserTID = 0;
57 static int GettingUserChannel = 0;
59 static Chat_user *Firstuser,*Curruser;
60 static Chat_command *Firstcommand,*Currcommand;
61 static Chat_channel *Firstchannel,*Currchannel;
65 Socket_connecting = 0;
67 SDL_zero(Original_nick_name);
69 SDL_zero(szChat_channel);
70 SDL_zero(Input_chat_buffer);
71 SDL_zero(Chat_tracker_id);
72 SDL_zero(Getting_user_channel_info_for);
73 SDL_zero(Getting_user_tracker_info_for);
74 Getting_user_channel_error = 0;
75 Getting_user_tracker_error = 0;
76 SDL_zero(User_req_tracker_id);
77 SDL_zero(User_req_channel);
81 Chat_server_connected = 0;
84 GettingChannelList = 0;
86 GettingUserChannel = 0;
92 //-2 Already connected
93 //-1 Failed to connect
96 // Call it once with the server IP address, and it will return immediately
97 // with 0. Keep calling it until it returns something other than 0
98 // note: the nickname may be changed if someone with that name already
99 // exists (Scourge1 for instance)
100 int ConnectToChatServer(char *serveraddr,char *nickname,char *trackerid)
103 char chat_server[50];
105 unsigned long argp = 1;
106 char signon_str[100];
108 //if(Socket_connected && ) return -2;
110 if(!Socket_connecting)
114 SDL_strlcpy(Nick_name, nickname, SDL_arraysize(Nick_name));
115 SDL_strlcpy(Original_nick_name, nickname, SDL_arraysize(Original_nick_name));
116 SDL_strlcpy(Chat_tracker_id, trackerid, SDL_arraysize(Chat_tracker_id));
120 Chat_server_connected = 0;
121 FlushChatCommandQueue();
123 p = strchr(serveraddr,':');
127 //AfxMessageBox("Invalid chat server, must be host.com:port (ie. irc.dal.net:6667)");
130 SDL_strlcpy(chat_server, serveraddr, SDL_arraysize(chat_server));
131 chat_server[p-serveraddr]='\0';
132 chat_port = (short)atoi(p+1);
135 //AfxMessageBox("Invalid chat port, must be host.com:port (ie. irc.dal.net:6667)");
139 Chatsock = socket(AF_INET,SOCK_STREAM,0);
140 if(INVALID_SOCKET == Chatsock)
142 //AfxMessageBox("Unable to open socket!");
146 memset( &Chataddr, 0, sizeof(struct sockaddr_in) );
147 Chataddr.sin_family = AF_INET;
148 Chataddr.sin_addr.s_addr = INADDR_ANY;
149 Chataddr.sin_port = 0;
151 if (SOCKET_ERROR==bind(Chatsock, (struct sockaddr *)&Chataddr, sizeof (struct sockaddr)))
153 //AfxMessageBox("Unable to bind socket!");
154 closesocket(Chatsock);
157 ioctlsocket(Chatsock,FIONBIO,&argp);
159 // first try and resolve by name
160 iaddr = inet_addr( chat_server );
161 if ( iaddr == INADDR_NONE ) {
163 he = gethostbyname(chat_server);
168 //AfxMessageBox("Unable to gethostbyname.\n");
170 // try and resolve by address
171 unsigned int n_order = inet_addr(chat_server);
172 he = gethostbyaddr((char*)&n_order,4,PF_INET);
180 iaddr = ((in_addr *)(he->h_addr))->s_addr;
183 Chataddr.sin_addr.s_addr = iaddr;
186 // Chataddr.sin_addr.s_addr = inet_addr(chat_server);
188 Chataddr.sin_port = htons( chat_port );
190 if(SOCKET_ERROR == connect(Chatsock,(struct sockaddr *)&Chataddr,sizeof(struct sockaddr_in)))
192 int error = WSAGetLastError();
193 if ( NETCALL_WOULDBLOCK(error) )
195 Socket_connecting = 1;
201 //This should never happen, connect should always return WSAEWOULDBLOCK
202 Socket_connecting = 1;
203 Socket_connected = 1;
209 if(Chat_server_connected)
214 if(!Socket_connected)
216 //Do a few select to check for an error, or to see if we are writeable (connected)
217 fd_set write_fds,error_fds;
218 struct timeval timeout;
224 FD_SET(Chatsock,&write_fds);
225 //Writable -- that means it's connected
226 if(select(Chatsock+1,NULL,&write_fds,NULL,&timeout))
229 SOCKLEN_T error_code_size = sizeof(error_code);
231 // check to make sure socket is *really* connected
232 int rc = getsockopt(Chatsock, SOL_SOCKET, SO_ERROR, (char *)&error_code, &error_code_size);
234 if(rc < 0 || error_code != 0)
236 shutdown(Chatsock, 2);
237 closesocket(Chatsock);
241 Socket_connected = 1;
242 SDL_snprintf(signon_str, SDL_arraysize(signon_str), NOX("/USER %s %s %s :%s"), NOX("user"), NOX("user"), NOX("user"), Chat_tracker_id);
243 SendChatString(signon_str,1);
244 SDL_snprintf(signon_str, SDL_arraysize(signon_str), NOX("/NICK %s"), Nick_name);
245 SendChatString(signon_str,1);
247 //Now we are waiting for Chat_server_connected
250 FD_SET(Chatsock,&error_fds);
251 //error -- that means it's not going to connect
252 if(select(Chatsock+1,NULL,NULL,&error_fds,&timeout))
254 shutdown(Chatsock, 2);
255 closesocket(Chatsock);
265 // Call it to close the connection. It returns immediately
266 void DisconnectFromChatServer()
268 if(!Socket_connected) return;
269 SendChatString(NOX("/QUIT"),1);
270 shutdown(Chatsock,2);
271 closesocket(Chatsock);
272 Socket_connecting = 0;
273 Socket_connected = 0;
274 Input_chat_buffer[0] = '\0';
286 Chat_server_connected = 0;
289 RemoveAllChatUsers();
290 FlushChatCommandQueue();
294 // returns NULL if no line is there to print, otherwise returns a string to
295 // print (all preformatted of course)
299 if(!Socket_connected) return NULL;
301 //ChatGetString will do the formatting
302 return ChatGetString();
306 // Send a string to be sent as chat, or scanned for messages (/msg <user>
308 const char * SendChatString(const char *line,int raw)
312 if(!Socket_connected) return NULL;
317 //Start off by getting the command
318 SDL_strlcpy(szCmd, GetWordNum(0,line+1), SDL_arraysize(szCmd));
319 if(SDL_strcasecmp(szCmd,NOX("msg"))==0)
321 SDL_strlcpy(szTarget, GetWordNum(1,line+1), SDL_arraysize(szTarget));
322 SDL_snprintf(szCmd, SDL_arraysize(szCmd), NOX("PRIVMSG %s :%s\n\r"), szTarget, line+strlen(NOX("/msg "))+strlen(szTarget)+1);
323 send(Chatsock,szCmd,strlen(szCmd),0);
324 szCmd[strlen(szCmd)-2]='\0';
325 return ParseIRCMessage(szCmd,MSG_LOCAL);
328 if(SDL_strcasecmp(szCmd,NOX("me"))==0)
330 SDL_snprintf(szCmd, SDL_arraysize(szCmd), NOX("PRIVMSG %s :\001ACTION %s\001\n\r"), szChat_channel, line+strlen(NOX("/me ")));
331 send(Chatsock,szCmd,strlen(szCmd),0);
332 szCmd[strlen(szCmd)-2]='\0';
333 return ParseIRCMessage(szCmd,MSG_LOCAL);
336 if(SDL_strcasecmp(szCmd,NOX("xyz"))==0)
338 //Special command to send raw irc commands
339 SDL_snprintf(szCmd, SDL_arraysize(szCmd), "%s\n\r", line+strlen(NOX("/xyz ")));
340 send(Chatsock,szCmd,strlen(szCmd),0);
343 if(SDL_strcasecmp(szCmd,NOX("list"))==0)
345 SDL_snprintf(szCmd, SDL_arraysize(szCmd), "%s\n\r", line+1);
346 send(Chatsock,szCmd,strlen(szCmd),0);
351 SDL_snprintf(szCmd, SDL_arraysize(szCmd), "%s\n\r", line+1);
352 send(Chatsock,szCmd,strlen(szCmd),0);
355 return XSTR("Unrecognized command",634);
360 if(szChat_channel[0])
364 sndstr.Format("PRIVMSG %s :%s\n\r",szChat_channel,line);
365 send(Chatsock,LPCSTR(sndstr),sndstr.GetLength(),0);
366 sndstr = sndstr.Left(sndstr.GetLength()-2);
367 return ParseIRCMessage((char *)LPCSTR(sndstr),MSG_LOCAL);
370 SDL_snprintf(szCmd, SDL_arraysize(szCmd), NOX("PRIVMSG %s :%s\n\r"), szChat_channel, line);
371 send(Chatsock,szCmd,strlen(szCmd),0);
372 if(strlen(szCmd) >= 2){
373 szCmd[strlen(szCmd)-2] = '\0';
374 return ParseIRCMessage(szCmd,MSG_LOCAL);
385 // Returns a structure which contains a command and possible some data (like
386 // a user joining or leaving) if one is waiting
387 // This tells you if you need to add a user from the userlist, remove a user,
388 // etc. Also for status messages, like if you get knocked
389 // off the server for some reason.
390 Chat_command *GetChatCommand()
392 if(!Socket_connected) return NULL;
393 return GetChatCommandFromQueue();
396 // This function returns a list of users in the current channel, in one
397 // string, separated by spaces, terminated by a null
398 // (Spaces aren't allowed as part of a nickname)
399 char *GetChatUserList()
401 int iuser_list_length = 0;;
407 if(!Socket_connected) return NULL;
409 Curruser = Firstuser;
412 iuser_list_length += strlen(Curruser->nick_name)+1;
413 Curruser = Curruser->next;
415 Curruser = Firstuser;
416 User_list = (char *)malloc(iuser_list_length+1);
420 SDL_strlcat(User_list, Curruser->nick_name, iuser_list_length+1);
421 SDL_strlcat(User_list, " ", iuser_list_length+1);
422 Curruser = Curruser->next;
428 // Call this to set/join a channel. Since we can't be sure that we will be
429 // able to join that channel, check it for completion
430 // You can't be in more than one channel at a time with this API, so you
431 // leave the current channel before trying to join
432 // a new one. Because of this if the join fails, make sure you try to join
433 // another channel, or the user wont be able to chat
436 // 1 successfully joined
437 int SetNewChatChannel(char *channel)
440 if(!Socket_connected) return -1;
441 if(Joining_channel==1)
443 if(Joined_channel==1)
449 else if(Joined_channel==-1)
451 //Error -- we got a message that the channel was invite only, or we were banned or something
453 SDL_zero(szChat_channel);
459 if(szChat_channel[0])
461 SDL_snprintf(partstr, SDL_arraysize(partstr), NOX("/PART %s"), szChat_channel);
462 SendChatString(partstr,1);
464 SDL_strlcpy(szChat_channel, channel, SDL_arraysize(szChat_channel));
465 SDL_snprintf(partstr, SDL_arraysize(partstr), NOX("/JOIN %s"), szChat_channel);
466 SendChatString(partstr,1);
475 char *ChatGetString(void)
478 struct timeval timeout;
482 static char return_string[MAXCHATBUFFER];
488 FD_SET(Chatsock,&read_fds);
489 //Writable -- that means it's connected
490 while(select(Chatsock+1,&read_fds,NULL,NULL,&timeout))
492 bytesread = recv(Chatsock,ch,1,0);
497 if((ch[0] == 0x0a)||(ch[0]==0x0d))
499 if(Input_chat_buffer[0]=='\0')
501 //Blank line, ignore it
504 SDL_strlcpy(return_string, Input_chat_buffer, SDL_arraysize(return_string));
505 Input_chat_buffer[0] = '\0';
507 p = ParseIRCMessage(return_string,MSG_REMOTE);
511 SDL_assert(strlen(Input_chat_buffer) < MAXCHATBUFFER-1);
512 SDL_strlcat(Input_chat_buffer, ch, SDL_arraysize(Input_chat_buffer));
516 //Select said we had read data, but 0 bytes read means disconnected
517 AddChatCommandToQueue(CC_DISCONNECTED,NULL,0);
526 const char * GetWordNum(int num, const char * l_String)
528 static char strreturn[600];
529 static char ptokstr[600];
530 char seps[10] = NOX(" \n\r\t");
531 char *token,*strstart;
535 SDL_strlcpy(ptokstr, l_String, SDL_arraysize(ptokstr));
537 token=strtok(ptokstr,seps);
539 for(int i=0;i!=num;i++)
541 token=strtok(NULL,seps);
545 SDL_strlcpy(strreturn, token, SDL_arraysize(strreturn));
551 //check for the ':' char....
554 //Its not pretty, but it works, return the rest of the string
555 SDL_strlcpy(strreturn, l_String+((token-strstart)+1), SDL_arraysize(strreturn));
558 //return the appropriate response.
562 int AddChatUser(const char *nickname)
564 Curruser = Firstuser;
567 if(SDL_strcasecmp(nickname,Curruser->nick_name)==0) return 0;
568 Curruser = Curruser->next;
571 Curruser = Firstuser;
574 Firstuser = (Chat_user *)malloc(sizeof(Chat_user));
575 SDL_assert(Firstuser);
576 SDL_strlcpy(Firstuser->nick_name, nickname, SDL_arraysize(Firstuser->nick_name));
577 Firstuser->next = NULL;
578 AddChatCommandToQueue(CC_USER_JOINING,nickname,strlen(nickname)+1);
583 while(Curruser->next)
585 Curruser = Curruser->next;
587 Curruser->next = (Chat_user *)malloc(sizeof(Chat_user));
588 Curruser = Curruser->next;
589 SDL_assert(Curruser);
590 SDL_strlcpy(Curruser->nick_name, nickname, SDL_arraysize(Curruser->nick_name));
591 Curruser->next = NULL;
592 AddChatCommandToQueue(CC_USER_JOINING,nickname,strlen(nickname)+1);
598 int RemoveChatUser(char *nickname)
600 Chat_user *prv_user = NULL;
602 Curruser = Firstuser;
605 if(SDL_strcasecmp(nickname,Curruser->nick_name)==0)
609 prv_user->next = Curruser->next;
614 Firstuser = Curruser->next;
616 AddChatCommandToQueue(CC_USER_LEAVING,Curruser->nick_name,strlen(Curruser->nick_name)+1);
621 Curruser = Curruser->next;
627 void RemoveAllChatUsers(void)
629 Chat_user *tmp_user = NULL;
630 Curruser = Firstuser;
633 tmp_user = Curruser->next;
634 AddChatCommandToQueue(CC_USER_LEAVING,Curruser->nick_name,strlen(Curruser->nick_name)+1);
642 char * ParseIRCMessage(char *Line, int iMode)
644 char szRemLine[MAXLOCALSTRING] ="";
645 const char *pszTempStr;
646 char szPrefix[MAXLOCALSTRING] = "";
647 char szHackPrefix[MAXLOCALSTRING] = "";
648 char szTarget[MAXLOCALSTRING] = "";
649 char szNick[MAXLOCALSTRING] = "";
650 char szCmd[MAXLOCALSTRING] = "";
651 char szCTCPCmd[MAXLOCALSTRING] = "";
653 static char szResponse[MAXLOCALSTRING] = "";
655 int iPrefixLen = 0; // JAS: Get rid of optimized warning
657 if(strlen(Line)>=MAXLOCALSTRING)
662 if(iMode==MSG_REMOTE)
664 SDL_strlcpy(szRemLine, Line, SDL_arraysize(szRemLine));
665 //Start by getting the prefix
669 pszTempStr=GetWordNum(0,Line+1);
670 SDL_strlcpy(szPrefix, pszTempStr, SDL_arraysize(szPrefix));
671 SDL_strlcpy(szHackPrefix, pszTempStr, SDL_arraysize(szHackPrefix));
672 SDL_strlcpy(szRemLine, Line+1+strlen(szPrefix), SDL_arraysize(szRemLine));
675 pszTempStr=strtok(szHackPrefix,"!");
678 SDL_strlcpy(szNick, pszTempStr, SDL_arraysize(szNick));
682 SDL_strlcpy(szNick, szPrefix, SDL_arraysize(szNick));
684 //strcpy(NewMsg.Nickname,szNick);
685 iPrefixLen=strlen(szPrefix);
687 else if(iMode==MSG_LOCAL)
689 SDL_strlcpy(szRemLine, Line, SDL_arraysize(szRemLine));
690 SDL_strlcpy(szNick, Nick_name, SDL_arraysize(szNick));
691 SDL_strlcpy(szPrefix, Nick_name, SDL_arraysize(szPrefix));
692 //strcpy(NewMsg.Nickname,szNick);
695 //Next is the command
696 pszTempStr=GetWordNum(0,szRemLine);
699 SDL_strlcpy(szCmd, pszTempStr, SDL_arraysize(szCmd));
703 //Shouldn't ever happen, but we can't be sure of what the host will send us.
707 //Move the szRemLine string up
708 SDL_strlcpy(szRemLine, Line+iPrefixLen+strlen(szCmd)+2, SDL_arraysize(szRemLine));
709 //Now parse the commands!
710 //printf("%s",szCmd);
711 if(SDL_strcasecmp(szCmd,NOX("PRIVMSG"))==0)
713 pszTempStr=GetWordNum(0,szRemLine);
714 SDL_strlcpy(szTarget, pszTempStr, SDL_arraysize(szTarget));
715 SDL_strlcpy(szRemLine, Line+iPrefixLen+strlen(szCmd)+strlen(szTarget)+4, SDL_arraysize(szRemLine));
716 if(szRemLine[0]==':')
718 SDL_strlcpy(szCTCPCmd, GetWordNum(0,szRemLine+1), SDL_arraysize(szCTCPCmd));
719 if(szCTCPCmd[strlen(szCTCPCmd)-1]==0x01) szCTCPCmd[strlen(szCTCPCmd)-1]=0x00;
724 SDL_strlcpy(szCTCPCmd, GetWordNum(0,szRemLine), SDL_arraysize(szCTCPCmd));
725 if(szCTCPCmd[strlen(szCTCPCmd)-1]==0x01) szCTCPCmd[strlen(szCTCPCmd)-1]=0x00;
727 if(szCTCPCmd[0]==0x01)
729 //Handle ctcp message
730 SDL_strlcpy(szRemLine, Line+iPrefixLen+strlen(szCmd)+strlen(szTarget)+strlen(szCTCPCmd)+6, SDL_arraysize(szRemLine));
731 szRemLine[strlen(szRemLine)-1]='\0';//null out the ending 0x01
732 if(SDL_strcasecmp(szCTCPCmd+1,NOX("ACTION"))==0)
735 SDL_snprintf(szResponse, SDL_arraysize(szResponse), "* %s %s", szNick, szRemLine);
740 SDL_strlcpy(szHackPrefix, Line+iPrefixLen+strlen(szCmd)+strlen(szTarget)+4, SDL_arraysize(szHackPrefix));
741 szRemLine[strlen(szRemLine)-1]='\0';
742 SDL_snprintf(szResponse, SDL_arraysize(szResponse), NOX("** CTCP %s %s %s"), szTarget, szCTCPCmd+1, szRemLine);
745 if(SDL_strcasecmp(szCTCPCmd+1,NOX("PING"))==0)
747 SDL_snprintf(szResponse, SDL_arraysize(szResponse), NOX("/NOTICE %s :\001PING %s\001"), szNick, szRemLine);//Don't need the trailing \001 because szremline has it.
748 SendChatString(szResponse,1);
751 if(SDL_strcasecmp(szCTCPCmd+1,NOX("VERSION"))==0)
753 //reply with a notice version & copyright
754 //sprintf(szTempLine,"NOTICE %s :\001VERSION Copyright(c)\001\n",szNick);
758 SDL_strlcpy(szRemLine, 1 + GetWordNum(0,Line+iPrefixLen+strlen(szCmd)+strlen(szTarget)+4), SDL_arraysize(szRemLine));
759 szRemLine[strlen(szRemLine)-1]='\0';
760 SDL_snprintf(szResponse, SDL_arraysize(szResponse), NOX("** CTCP Message from %s (%s)"), szNick, szRemLine);
764 //differentiate between channel and private
767 pszTempStr=GetWordNum(0,szRemLine);
768 SDL_snprintf(szResponse, SDL_arraysize(szResponse), "[%s] %s", szNick, pszTempStr);
773 if(iMode == MSG_LOCAL)
775 pszTempStr=GetWordNum(0,szRemLine);
776 SDL_snprintf(szResponse, SDL_arraysize(szResponse), NOX("Private Message to <%s>: %s"), szNick, pszTempStr);
780 pszTempStr=GetWordNum(0,szRemLine);
781 SDL_snprintf(szResponse, SDL_arraysize(szResponse), NOX("Private Message from <%s>: %s"), szNick, pszTempStr);
787 //don't handle any other messages locally.
793 if(SDL_strcasecmp(szCmd,NOX("NOTICE"))==0)
797 pszTempStr=GetWordNum(0,szRemLine);
798 SDL_strlcpy(szTarget, pszTempStr, SDL_arraysize(szTarget));
799 SDL_strlcpy(szRemLine, Line+iPrefixLen+strlen(szCmd)+strlen(szTarget)+4, SDL_arraysize(szRemLine));
800 if(szRemLine[0]==':')
802 SDL_strlcpy(szCTCPCmd, GetWordNum(0,szRemLine+1), SDL_arraysize(szCTCPCmd));
803 if(szCTCPCmd[strlen(szCTCPCmd)-1]==0x01) szCTCPCmd[strlen(szCTCPCmd)-1]=0x00;
808 SDL_strlcpy(szCTCPCmd, GetWordNum(0,szRemLine), SDL_arraysize(szCTCPCmd));
809 if(szCTCPCmd[strlen(szCTCPCmd)-1]==0x01) szCTCPCmd[strlen(szCTCPCmd)-1]=0x00;
811 if(szCTCPCmd[0]==0x01)
813 //Handle ctcp message
814 SDL_strlcpy(szRemLine, Line+iPrefixLen+strlen(szCmd)+strlen(szTarget)+strlen(szCTCPCmd)+6, SDL_arraysize(szRemLine));
815 szRemLine[strlen(szRemLine)-1]='\0';//null out the ending 0x01
816 if(SDL_strcasecmp(szCTCPCmd+1,NOX("PING"))==0)
818 //This is a ping response, figure out time and print
819 //sprintf(NewMsg.Message,"** Ping Response from %s: %ums",szNick,ulping);
824 SDL_strlcpy(szRemLine, 1 + GetWordNum(0,Line+iPrefixLen+strlen(szCmd)+strlen(szTarget)+4), SDL_arraysize(szRemLine));
825 szRemLine[strlen(szRemLine)-1]='\0';
826 SDL_snprintf(szResponse, SDL_arraysize(szResponse), XSTR("** CTCP Message from %s (%s)",635), szNick, szRemLine);
830 SDL_snprintf(szResponse, SDL_arraysize(szResponse), "%s", szRemLine);
833 if(SDL_strcasecmp(szCmd,NOX("JOIN"))==0)
836 if(SDL_strcasecmp(Nick_name,szNick)==0)
839 //if(strcmpi(szChat_channel,GetWordNum(0,szRemLine))==0)
842 if(SDL_strcasecmp(szChat_channel,NOX("#autoselect"))==0)
844 SDL_strlcpy(szChat_channel, GetWordNum(0,szRemLine), SDL_arraysize(szChat_channel));
845 AddChatCommandToQueue(CC_YOURCHANNEL,szChat_channel,strlen(szChat_channel)+1);
854 pszTempStr=GetWordNum(0,szRemLine);
855 SDL_strlcpy(szTarget, pszTempStr, SDL_arraysize(szTarget));
856 //strcpy(szRemLine,Line+iPrefixLen+strlen(szCmd)+strlen(szTarget)+3);
858 //strcpy(NewMsg.Channel,szTarget);
861 SDL_snprintf(szResponse, SDL_arraysize(szResponse), XSTR("** %s has joined %s",636), szNick, szTarget);
862 return NULL;//szResponse;
863 //Add them to the userlist too!
865 if(SDL_strcasecmp(szCmd,NOX("PART"))==0)
867 pszTempStr=GetWordNum(0,szRemLine);
868 SDL_strlcpy(szTarget, pszTempStr, SDL_arraysize(szTarget));
869 SDL_strlcpy(szRemLine, Line+iPrefixLen+strlen(szCmd)+strlen(szTarget)+3, SDL_arraysize(szRemLine));
871 if(SDL_strcasecmp(Nick_name,szNick)==0)
874 //szChat_channel[0]=NULL;
875 RemoveAllChatUsers();
878 RemoveChatUser(szNick);
880 //Remove them to the userlist too!
882 if(SDL_strcasecmp(szCmd,NOX("KICK"))==0)
884 pszTempStr=GetWordNum(0,szRemLine);
885 SDL_strlcpy(szTarget, pszTempStr, SDL_arraysize(szTarget));
886 pszTempStr=GetWordNum(1,szRemLine);
887 SDL_strlcpy(szHackPrefix, pszTempStr, SDL_arraysize(szHackPrefix));
888 pszTempStr=GetWordNum(2,szRemLine);
890 if(SDL_strcasecmp(Nick_name,GetWordNum(1,szRemLine))==0)
893 szChat_channel[0]='\0';
895 AddChatCommandToQueue(CC_KICKED,NULL,0);
896 RemoveAllChatUsers();
898 SDL_snprintf(szResponse, SDL_arraysize(szResponse), XSTR("*** %s has kicked %s from channel %s (%s)",637), szNick, szHackPrefix, szTarget, pszTempStr);
899 //Remove them to the userlist too!
900 RemoveChatUser(szNick);
904 if(SDL_strcasecmp(szCmd,NOX("NICK"))==0)
907 if(SDL_strcasecmp(Nick_name,szNick)==0)
910 SDL_strlcpy(Nick_name, GetWordNum(0,szRemLine), SDL_arraysize(Nick_name));
913 SDL_snprintf(nicks, SDL_arraysize(nicks), "%s %s", szNick, GetWordNum(0,szRemLine));
914 AddChatCommandToQueue(CC_NICKCHANGED,nicks,strlen(nicks)+1);
915 RemoveChatUser(szNick);
916 AddChatUser(GetWordNum(0,szRemLine));
917 SDL_snprintf(szResponse, SDL_arraysize(szResponse), XSTR("*** %s is now known as %s",638), szNick, GetWordNum(0,szRemLine));
920 if(SDL_strcasecmp(szCmd,NOX("PING"))==0)
922 //respond with pong (GetWordNum(0,szRemLine))
923 SDL_snprintf(szResponse, SDL_arraysize(szResponse), NOX("/PONG :%s"), GetWordNum(0,szRemLine));
924 SendChatString(szResponse,1);
927 if(SDL_strcasecmp(szCmd,NOX("MODE"))==0)
934 if(SDL_strcasecmp(szCmd,"401")==0)
936 //This is whois user info, we can get their tracker info from here. -5
937 char szWhoisUser[33];
938 SDL_strlcpy(szWhoisUser, GetWordNum(1,szRemLine), SDL_arraysize(szWhoisUser));
939 Getting_user_tracker_error = 1;
940 Getting_user_channel_error = 1;
942 SDL_snprintf(szResponse, SDL_arraysize(szResponse), XSTR("**Error: %s is not online!",639), szWhoisUser);
946 if(SDL_strcasecmp(szCmd,"311")==0)
948 char szWhoisUser[33];
949 SDL_strlcpy(szWhoisUser, GetWordNum(1,szRemLine), SDL_arraysize(szWhoisUser));
950 //This is whois user info, we can get their tracker info from here. -5
951 //if(strcmpi(Getting_user_tracker_info_for,szWhoisUser)==0)
953 SDL_strlcpy(User_req_tracker_id, GetWordNum(5,szRemLine), SDL_arraysize(User_req_tracker_id));
957 if(SDL_strcasecmp(szCmd,"319")==0)
959 char szWhoisUser[33];
960 SDL_strlcpy(szWhoisUser, GetWordNum(1,szRemLine), SDL_arraysize(szWhoisUser));
961 //This is whois channel info -- what channel they are on -2
962 //if(strcmpi(Getting_user_channel_info_for,szWhoisUser)==0)
964 SDL_strlcpy(User_req_channel, GetWordNum(2,szRemLine), SDL_arraysize(User_req_channel));
969 //End of whois and we didn't get a channel means they aren't in a channel.
970 if(SDL_strcasecmp(szCmd,"318")==0)
972 if(!*User_req_channel)
974 User_req_channel[0] = '*';
979 if(SDL_strcasecmp(szCmd,"321")==0)
981 //start of channel list
983 GettingChannelList = 1;
986 if(SDL_strcasecmp(szCmd,"322")==0)
989 if(GettingChannelList == 1)
991 char channel_list_name[33];
993 SDL_strlcpy(sztopic, GetWordNum(3,szRemLine), SDL_arraysize(sztopic));
994 SDL_strlcpy(channel_list_name, GetWordNum(1,szRemLine), SDL_arraysize(channel_list_name));
995 AddChannel(channel_list_name,(short)atoi(GetWordNum(2,szRemLine)),sztopic);
999 if(SDL_strcasecmp(szCmd,"323")==0)
1001 //end of channel list
1002 GettingChannelList = 2;
1005 if(SDL_strcasecmp(szCmd,"324")==0)
1011 if(SDL_strcasecmp(szCmd,"332")==0)
1013 //Channel Topic, update status bar.
1014 if(SDL_strcasecmp(szChat_channel,szTarget)==0)
1016 //strncpy(szChanTopic,GetWordNum(2,szRemLine),70);
1018 //sprintf(NewMsg.Message,"*** %s has changed the topic to: %s",szNick,GetWordNum(2,szRemLine));
1022 if(SDL_strcasecmp(szCmd,NOX("TOPIC"))==0)
1024 //Channel Topic, update status bar.
1025 if(SDL_strcasecmp(szChat_channel,szTarget)==0)
1027 //strncpy(szChanTopic,GetWordNum(1,szRemLine),70);
1029 //sprintf(NewMsg.Message,"*** %s has changed the topic to: %s",szNick,GetWordNum(1,szRemLine));
1032 if(SDL_strcasecmp(szCmd,NOX("QUIT"))==0)
1035 RemoveChatUser(szNick);
1038 if(SDL_strcasecmp(szCmd,"376")==0) //end of motd, trigger autojoin...
1040 if (!Chat_server_connected)
1042 Chat_server_connected=1;
1046 SDL_strlcpy(szResponse, PXO_CHAT_END_OF_MOTD_PREFIX, SDL_arraysize(szResponse));
1049 if((SDL_strcasecmp(szCmd,"377")==0)||
1050 (SDL_strcasecmp(szCmd,"372")==0)||
1051 (SDL_strcasecmp(szCmd,"372")==0)
1055 //Stip the message, and display it.
1056 pszTempStr=GetWordNum(3,Line);
1057 SDL_strlcpy(szResponse, PXO_CHAT_MOTD_PREFIX, SDL_arraysize(szResponse));
1058 SDL_strlcat(szResponse, pszTempStr, SDL_arraysize(szResponse));
1061 //Ignore these messages
1062 if(((SDL_strcasecmp(szCmd,"366")==0))||
1063 (SDL_strcasecmp(szCmd,"333")==0) || //Who set the topic
1064 (SDL_strcasecmp(szCmd,"329")==0)) //Time Channel created
1066 (SDL_strcasecmp(szCmd,"305")==0) ||
1067 (SDL_strcasecmp(szCmd,"306")==0) ||
1068 (SDL_strcasecmp(szCmd,"311")==0) || //WHOIS stuff
1069 (SDL_strcasecmp(szCmd,"312")==0) ||
1070 (SDL_strcasecmp(szCmd,"313")==0) ||
1071 (SDL_strcasecmp(szCmd,"317")==0) ||
1072 (SDL_strcasecmp(szCmd,"318")==0) ||
1073 (SDL_strcasecmp(szCmd,"319")==0) ||
1079 if(SDL_strcasecmp(szCmd,"353")==0)
1082 //Names in the channel.
1083 pszTempStr = GetWordNum(3,Line+iPrefixLen+strlen(szCmd)+2);
1084 SDL_strlcpy(szRemLine, pszTempStr, SDL_arraysize(szRemLine));
1085 pszTempStr = strtok(szRemLine," ");
1089 if(pszTempStr[0]=='@')
1091 AddChatUser(pszTempStr+1);
1093 else if(pszTempStr[0]=='+')
1095 AddChatUser(pszTempStr+1);
1099 AddChatUser(pszTempStr);
1101 pszTempStr=strtok(NULL," ");
1106 if((SDL_strcasecmp(szCmd,"001")==0)||
1107 (SDL_strcasecmp(szCmd,"002")==0)||
1108 (SDL_strcasecmp(szCmd,"003")==0)||
1109 (SDL_strcasecmp(szCmd,"004")==0)||
1110 (SDL_strcasecmp(szCmd,"251")==0)||
1111 (SDL_strcasecmp(szCmd,"254")==0)||
1112 (SDL_strcasecmp(szCmd,"255")==0)||
1113 (SDL_strcasecmp(szCmd,"265")==0)||
1114 (SDL_strcasecmp(szCmd,"375")==0)||
1115 (SDL_strcasecmp(szCmd,"372")==0)||
1116 (SDL_strcasecmp(szCmd,"375")==0)
1119 // Stip the message, and display it.
1120 // pszTempStr = GetWordNum(3, Line);
1121 // strcpy(szResponse, PXO_CHAT_MOTD_PREFIX);
1122 // strcat(szResponse, pszTempStr);
1124 // return szResponse;
1126 if(SDL_strcasecmp(szCmd,"432")==0)
1129 SDL_strlcpy(szResponse, XSTR("Your nickname contains invalid characters",640), SDL_arraysize(szResponse));
1130 AddChatCommandToQueue(CC_DISCONNECTED,NULL,0);
1133 if(SDL_strcasecmp(szCmd,"433")==0)
1137 SDL_snprintf(new_nick, SDL_arraysize(new_nick), "%s%d", Original_nick_name, Nick_variety);
1138 SDL_strlcpy(Nick_name, new_nick, SDL_arraysize(Nick_name));
1140 SDL_snprintf(szResponse, SDL_arraysize(szResponse), NOX("/NICK %s"), new_nick);
1141 SendChatString(szResponse,1);
1145 SDL_strlcpy(szResponse, Line, SDL_arraysize(szResponse));
1146 //return szResponse;
1152 void AddChatCommandToQueue(int command,const void *data,int len)
1154 Currcommand = Firstcommand;
1155 if(Firstcommand==NULL)
1157 Firstcommand = (Chat_command *)malloc(sizeof(Chat_command));
1158 SDL_assert(Firstcommand);
1159 Firstcommand->next = NULL;
1160 Currcommand = Firstcommand;
1164 while(Currcommand->next)
1166 Currcommand = Currcommand->next;
1168 Currcommand->next = (Chat_command *)malloc(sizeof(Chat_command));
1169 SDL_assert(Currcommand->next);
1170 Currcommand = Currcommand->next;
1172 Currcommand->command = (short)command;
1173 if(len&&data) memcpy(&Currcommand->data,data,len);
1174 Currcommand->next = NULL;
1178 Chat_command *GetChatCommandFromQueue(void)
1180 static Chat_command response_cmd;
1181 Chat_command *tmp_cmd;
1182 if(!Firstcommand) return NULL;
1183 Currcommand = Firstcommand;
1184 memcpy(&response_cmd,Currcommand,sizeof(Chat_command));
1185 tmp_cmd = Currcommand->next;
1187 Firstcommand = tmp_cmd;
1188 return &response_cmd;
1191 void FlushChatCommandQueue(void)
1193 Chat_command *tmp_cmd;
1194 Currcommand = Firstcommand;
1198 tmp_cmd = Currcommand->next;
1200 Currcommand = tmp_cmd;
1202 Firstcommand = NULL;
1206 void FlushChannelList(void)
1208 Chat_channel *tmp_chan;
1209 Currchannel = Firstchannel;
1213 tmp_chan = Currchannel->next;
1215 Currchannel = tmp_chan;
1217 Firstchannel = NULL;
1221 char *GetChannelList(void)
1223 int ichan_list_length = 0;
1224 char sznumusers[10];
1226 if(GettingChannelList != 2) return NULL;
1227 if(!Socket_connected) return NULL;
1236 Currchannel = Firstchannel;
1239 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
1240 Currchannel = Currchannel->next;
1242 Currchannel = Firstchannel;
1243 Chan_list = (char *)malloc(ichan_list_length+1);
1244 Chan_list[0] = '\0';
1247 SDL_strlcat(Chan_list, "$", ichan_list_length+1);
1248 SDL_strlcat(Chan_list, Currchannel->channel_name, ichan_list_length+1);
1249 SDL_strlcat(Chan_list, " ", ichan_list_length+1);
1250 SDL_snprintf(sznumusers, SDL_arraysize(sznumusers), "%d ", Currchannel->users);
1251 SDL_strlcat(Chan_list, sznumusers, ichan_list_length+1);
1252 SDL_strlcat(Chan_list, Currchannel->topic, ichan_list_length+1);//fgets
1253 SDL_strlcat(Chan_list, " ", ichan_list_length+1);
1254 Currchannel = Currchannel->next;
1257 GettingChannelList = 0;
1261 void AddChannel(char *channel,unsigned short numusers,char *topic)
1263 Currchannel = Firstchannel;
1264 if(Firstchannel==NULL)
1266 Firstchannel = (Chat_channel *)malloc(sizeof(Chat_channel));
1267 SDL_assert(Firstchannel);
1268 SDL_strlcpy(Firstchannel->channel_name, channel, SDL_arraysize(Firstchannel->channel_name));
1269 SDL_strlcpy(Firstchannel->topic, topic, SDL_arraysize(Firstchannel->topic));
1270 Firstchannel->users = numusers;
1271 Firstchannel->next = NULL;
1272 Currchannel = Firstchannel;
1276 while(Currchannel->next)
1278 Currchannel = Currchannel->next;
1280 Currchannel->next = (Chat_channel *)malloc(sizeof(Chat_channel));
1281 SDL_assert(Currchannel->next);
1282 Currchannel = Currchannel->next;
1283 SDL_strlcpy(Currchannel->channel_name, channel, SDL_arraysize(Currchannel->channel_name));
1284 SDL_strlcpy(Currchannel->topic, topic, SDL_arraysize(Currchannel->topic));
1285 Currchannel->users = numusers;
1287 Currchannel->next = NULL;
1292 char *GetTrackerIdByUser(char *nickname)
1294 char szWhoisCmd[100];
1299 if(Getting_user_tracker_error)
1301 Getting_user_tracker_error = 0;
1306 if(*User_req_tracker_id)
1309 return User_req_tracker_id;
1314 SDL_strlcpy(Getting_user_tracker_info_for, nickname, SDL_arraysize(Getting_user_tracker_info_for));
1315 SDL_snprintf(szWhoisCmd, SDL_arraysize(szWhoisCmd), NOX("/WHOIS %s"), nickname);
1316 User_req_tracker_id[0] = '\0';
1317 SendChatString(szWhoisCmd,1);
1323 char *GetChannelByUser(char *nickname)
1325 char szWhoisCmd[100];
1327 if(GettingUserChannel)
1329 if(Getting_user_channel_error)
1331 Getting_user_channel_error = 0;
1332 GettingUserChannel = 0;
1335 if(*User_req_channel)
1337 GettingUserChannel = 0;
1338 return User_req_channel;
1343 SDL_strlcpy(Getting_user_channel_info_for, nickname, SDL_arraysize(Getting_user_channel_info_for));
1344 User_req_channel[0] = '\0';
1345 SDL_snprintf(szWhoisCmd, SDL_arraysize(szWhoisCmd), NOX("/WHOIS %s"), nickname);
1346 SendChatString(szWhoisCmd,1);
1347 GettingUserChannel = 1;