]> icculus.org git repositories - taylor/freespace2.git/blob - src/network/chat_api.cpp
replace bad sprintf's
[taylor/freespace2.git] / src / network / chat_api.cpp
1 /*
2  * Copyright (C) Volition, Inc. 2005.  All rights reserved.
3  * 
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 
6  * source.
7  *
8 */
9
10
11 #ifdef PLAT_UNIX
12 #include <sys/time.h>
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>
18 #include <errno.h>
19 #include <arpa/inet.h>
20 #include <netdb.h>
21
22 #define WSAGetLastError()  (errno)
23 #else
24 #include <winsock.h>
25 typedef int socklen_t;
26 #endif
27
28 #include "pstypes.h"
29 #include "chat_api.h"
30
31 #define MAXCHATBUFFER   500
32
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;
57
58 static Chat_user *Firstuser,*Curruser;
59 static Chat_command *Firstcommand,*Currcommand;
60 static Chat_channel *Firstchannel,*Currchannel;
61
62 void ChatInit(void)
63 {
64         Socket_connecting = 0;
65         SDL_zero(Nick_name);
66         SDL_zero(Original_nick_name);
67         Nick_variety = 0;
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);
77         User_list = NULL;
78         Chan_list = NULL;
79         Socket_connected = 0;
80         Chat_server_connected = 0;
81         Joining_channel = 0;
82         Joined_channel = 0;
83         GettingChannelList = 0;
84         GettingUserTID = 0;
85         GettingUserChannel = 0;
86
87 }
88
89
90 // Return codes:
91 //-2 Already connected
92 //-1 Failed to connect
93 // 0 Connecting
94 // 1 Connected
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)
100 {
101         short chat_port;
102         char chat_server[50];
103         char *p;
104         unsigned long argp = 1;
105         char signon_str[100];
106
107         //if(Socket_connected && ) return -2;
108
109         if(!Socket_connecting)
110         {
111                 unsigned long iaddr;
112
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));
116                 
117                 Firstuser = NULL;
118                 Firstcommand = NULL;
119                 Chat_server_connected = 0;
120                 FlushChatCommandQueue();
121
122                 p = strchr(serveraddr,':');
123
124                 if(NULL==p)
125                 {
126                         //AfxMessageBox("Invalid chat server, must be host.com:port (ie. irc.dal.net:6667)");
127                         return -1;
128                 }
129                 SDL_strlcpy(chat_server, serveraddr, sizeof(chat_server));
130                 chat_server[p-serveraddr]='\0';
131                 chat_port = (short)atoi(p+1);
132                 if(0==chat_port)
133                 {
134                         //AfxMessageBox("Invalid chat port, must be host.com:port (ie. irc.dal.net:6667)");
135                         return -1;
136                 }
137
138                 Chatsock = socket(AF_INET,SOCK_STREAM,0);
139                 if(INVALID_SOCKET == Chatsock)
140                 {
141                         //AfxMessageBox("Unable to open socket!");
142                         return -1;
143                 }
144
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;
149                 
150                 if (SOCKET_ERROR==bind(Chatsock, (SOCKADDR*)&Chataddr, sizeof (sockaddr))) 
151                 {
152                         //AfxMessageBox("Unable to bind socket!");
153                         return -1;
154                 }
155                 ioctlsocket(Chatsock,FIONBIO,&argp);
156                 
157                 // first try and resolve by name
158                 iaddr = inet_addr( chat_server );
159                 if ( iaddr == INADDR_NONE ) {   
160                         HOSTENT *he;
161                         he = gethostbyname(chat_server);
162                         if(!he)
163                         {
164                                 return 0;
165                                 /*
166                                 //AfxMessageBox("Unable to gethostbyname.\n");
167
168                                 // try and resolve by address                   
169                                 unsigned int n_order = inet_addr(chat_server);
170                                 he = gethostbyaddr((char*)&n_order,4,PF_INET);                                  
171
172                                 if(!he){
173                                         return -1;
174                                 }
175                                 */
176                         }
177                         memcpy(&iaddr, he->h_addr_list[0],4);
178                 }
179                 
180                 memcpy(&Chataddr.sin_addr.s_addr, &iaddr,4); //&iaddr, 4);                              
181
182                 
183                 // Chataddr.sin_addr.s_addr = inet_addr(chat_server);
184
185                 Chataddr.sin_port = htons( chat_port );
186
187                 if(SOCKET_ERROR == connect(Chatsock,(SOCKADDR *)&Chataddr,sizeof(SOCKADDR_IN)))
188                 {
189                         if(WSAEWOULDBLOCK == WSAGetLastError())
190                         {
191                                 Socket_connecting = 1;
192                                 return 0;
193                         }
194                 }
195                 else
196                 {
197                         //This should never happen, connect should always return WSAEWOULDBLOCK
198                         Socket_connecting = 1;
199                         Socket_connected = 1;
200                         return 1;
201                 }
202         }
203         else
204         {
205                 if(Chat_server_connected)
206                 {
207                         return 1;
208                 }
209
210                 if(!Socket_connected)
211                 {
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;                
214                         TIMEVAL timeout;   
215                         
216                         timeout.tv_sec=0;            
217                         timeout.tv_usec=0;
218                         
219                         FD_ZERO(&write_fds);
220                         FD_SET(Chatsock,&write_fds);    
221                         //Writable -- that means it's connected
222                         if(select(0,NULL,&write_fds,NULL,&timeout))
223                         {
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);
229                                 return 0;
230                                 //Now we are waiting for Chat_server_connected
231                         }
232                         FD_ZERO(&error_fds);
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))
236                         {
237                                 return -1;
238                         }
239                         return 0;
240                 }
241         }
242
243         return 0;
244 }
245
246 // Call it to close the connection. It returns immediately
247 void DisconnectFromChatServer()
248 {
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';
256         if(User_list)
257         {
258                 free(User_list);
259                 User_list = NULL;
260         }
261         if(Chan_list)
262         {
263                 free(Chan_list);
264                 Chan_list = NULL;
265         }
266         
267         Chat_server_connected = 0;
268         Joining_channel = 0;
269         Joined_channel = 0;
270         RemoveAllChatUsers();
271         FlushChatCommandQueue();
272         return;
273 }
274
275 // returns NULL if no line is there to print, otherwise returns a string to
276 // print (all preformatted of course)
277 char * GetChatText()
278 {
279
280         if(!Socket_connected) return NULL;
281
282         //ChatGetString will do the formatting
283         return ChatGetString();
284
285 }
286
287 // Send a string to be sent as chat, or scanned for messages (/msg <user>
288 // string)
289 const char * SendChatString(const char *line,int raw)
290 {
291         char szCmd[200];
292         char szTarget[50];
293         if(!Socket_connected) return NULL;
294         
295         if(line[0]=='/')
296         {
297
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)
301                 {
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);
307
308                 }
309                 if(SDL_strcasecmp(szCmd,NOX("me"))==0)
310                 {
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);
315
316                 }
317                 if(SDL_strcasecmp(szCmd,NOX("xyz"))==0)
318                 {
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);
322                         return NULL;
323                 }
324                 if(SDL_strcasecmp(szCmd,NOX("list"))==0)
325                 {
326                         SDL_snprintf(szCmd, sizeof(szCmd), "%s\n\r", line+1);
327                         send(Chatsock,szCmd,strlen(szCmd),0);
328                         return NULL;
329                 }
330                 if(raw)
331                 {
332                         SDL_snprintf(szCmd, sizeof(szCmd), "%s\n\r", line+1);
333                         send(Chatsock,szCmd,strlen(szCmd),0);
334                         return NULL;
335                 }
336                 return XSTR("Unrecognized command",634);
337                 
338         }
339         else
340         {
341                 if(szChat_channel[0])
342                 {
343                         /*
344                         CString sndstr;
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);
349                         */
350
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);
356                         }                       
357
358                         return NULL;
359                 }
360         }
361         
362         return NULL;
363 }
364
365
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()
372 {
373         if(!Socket_connected) return NULL;
374         return GetChatCommandFromQueue();
375 }
376
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()
381 {
382         int iuser_list_length = 0;;
383         if(User_list)
384         {
385                 free(User_list);
386                 User_list = NULL;
387         }
388         if(!Socket_connected) return NULL;
389         
390         Curruser = Firstuser;
391         while(Curruser) 
392         {
393                 iuser_list_length += strlen(Curruser->nick_name)+1;
394                 Curruser = Curruser->next;
395         }
396         Curruser = Firstuser;
397         User_list = (char *)malloc(iuser_list_length+1);
398         User_list[0] = '\0';
399         while(Curruser) 
400         {
401                 strcat(User_list,Curruser->nick_name);
402                 strcat(User_list," ");
403                 Curruser = Curruser->next;
404         }
405
406         return User_list;
407 }
408
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
415 //-1 Failed to join
416 // 0 joining
417 // 1 successfully joined
418 int SetNewChatChannel(char *channel)
419 {
420         char partstr[100];
421         if(!Socket_connected) return -1;
422         if(Joining_channel==1) 
423         {
424                 if(Joined_channel==1) 
425                 {
426                         //We made it in!
427                         Joining_channel = 0;
428                         return 1;
429                 }
430                 else if(Joined_channel==-1) 
431                 {
432                         //Error -- we got a message that the channel was invite only, or we were banned or something
433                         Joining_channel = 0;
434                         SDL_zero(szChat_channel);
435                         return -1;
436                 }
437         }
438         else
439         {
440                 if(szChat_channel[0])
441                 {
442                         SDL_snprintf(partstr, sizeof(partstr), NOX("/PART %s"), szChat_channel);
443                         SendChatString(partstr,1);
444                 }
445                 SDL_strlcpy(szChat_channel, channel, sizeof(szChat_channel));
446                 SDL_snprintf(partstr, sizeof(partstr), NOX("/JOIN %s"), szChat_channel);
447                 SendChatString(partstr,1);
448                 Joining_channel = 1;
449                 Joined_channel = 0;
450         }
451         
452         return 0;
453 }
454
455
456 char *ChatGetString(void)
457 {
458         fd_set read_fds;                   
459         TIMEVAL timeout; 
460         char ch[2];
461         char *p;
462         int bytesread;
463         static char return_string[MAXCHATBUFFER];
464         
465         timeout.tv_sec=0;            
466         timeout.tv_usec=0;
467         
468         FD_ZERO(&read_fds);
469         FD_SET(Chatsock,&read_fds);    
470         //Writable -- that means it's connected
471         while(select(0,&read_fds,NULL,NULL,&timeout))
472         {
473                 bytesread = recv(Chatsock,ch,1,0);
474                 if(bytesread)
475                 {
476                         ch[1] = '\0';
477                         
478                         if((ch[0] == 0x0a)||(ch[0]==0x0d))
479                         {
480                                 if(Input_chat_buffer[0]=='\0')
481                                 {
482                                         //Blank line, ignore it
483                                         return NULL;
484                                 }
485                                 SDL_strlcpy(return_string, Input_chat_buffer, sizeof(return_string));
486                                 Input_chat_buffer[0] = '\0';
487                                 
488                                 p = ParseIRCMessage(return_string,MSG_REMOTE);
489                                 
490                                 return p;
491                         }
492                         SDL_assert(strlen(Input_chat_buffer) < MAXCHATBUFFER-1);
493                         SDL_strlcat(Input_chat_buffer, ch, sizeof(Input_chat_buffer));
494                 }
495                 else
496                 {
497                         //Select said we had read data, but 0 bytes read means disconnected
498                         AddChatCommandToQueue(CC_DISCONNECTED,NULL,0);
499                         return NULL;
500                 }
501                 
502         }
503         return NULL;
504 }
505
506
507 const char * GetWordNum(int num, const char * l_String)
508 {
509         static char strreturn[600];
510         static char ptokstr[600];
511         char seps[10] = NOX(" \n\r\t");
512         char *token,*strstart;
513
514         strstart = ptokstr;
515
516         SDL_strlcpy(ptokstr, l_String, sizeof(ptokstr));
517
518         token=strtok(ptokstr,seps);
519
520         for(int i=0;i!=num;i++)
521         {
522                 token=strtok(NULL,seps);
523         }
524         if(token)
525         {
526                 SDL_strlcpy(strreturn, token, sizeof(strreturn));
527         }
528         else
529         {
530                 return "";
531         }
532         //check for the ':' char....
533         if(token[0]==':')
534         {
535                 //Its not pretty, but it works, return the rest of the string
536                 SDL_strlcpy(strreturn, l_String+((token-strstart)+1), sizeof(strreturn));
537         }
538
539         //return the appropriate response.
540         return strreturn;
541 }
542
543 int AddChatUser(const char *nickname)
544 {
545         Curruser = Firstuser;
546         while(Curruser) 
547         {
548                 if(SDL_strcasecmp(nickname,Curruser->nick_name)==0) return 0;
549                 Curruser = Curruser->next;
550         }
551
552         Curruser = Firstuser;
553         if(Firstuser==NULL)
554         {
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);
560                 return 1;
561         }
562         else
563         {
564                 while(Curruser->next) 
565                 {
566                         Curruser = Curruser->next;
567                 }
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);
574                 return 1;
575         }
576
577 }
578
579 int RemoveChatUser(char *nickname)
580 {
581         Chat_user *prv_user = NULL;
582         
583         Curruser = Firstuser;
584         while(Curruser) 
585         {
586                 if(SDL_strcasecmp(nickname,Curruser->nick_name)==0)
587                 {
588                         if(prv_user)
589                         {
590                                 prv_user->next = Curruser->next;
591
592                         }
593                         else
594                         {
595                                 Firstuser = Curruser->next;
596                         }
597                         AddChatCommandToQueue(CC_USER_LEAVING,Curruser->nick_name,strlen(Curruser->nick_name)+1);
598                         free(Curruser);
599                         return 1;
600                 }               
601                 prv_user = Curruser;
602                 Curruser = Curruser->next;
603         }
604         return 0;
605
606 }
607
608 void RemoveAllChatUsers(void)
609 {
610         Chat_user *tmp_user = NULL;
611         Curruser = Firstuser;
612         while(Curruser) 
613         {
614                 tmp_user = Curruser->next;
615                 AddChatCommandToQueue(CC_USER_LEAVING,Curruser->nick_name,strlen(Curruser->nick_name)+1);
616                 free(Curruser);
617                 Curruser = tmp_user;
618         }
619         Firstuser = NULL;
620 }
621
622
623 char * ParseIRCMessage(char *Line, int iMode)
624 {
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] = "";
633
634         static char szResponse[MAXLOCALSTRING] = "";
635
636         int iNickLen;
637         int iPrefixLen = 0;     // JAS: Get rid of optimized warning
638
639         if(strlen(Line)>=MAXLOCALSTRING)
640         {
641                 return NULL; 
642         }
643         //Nick included....
644         if(iMode==MSG_REMOTE)
645         {
646                 SDL_strlcpy(szRemLine, Line, sizeof(szRemLine));
647                 //Start by getting the prefix
648                 if(Line[0]==':')
649                 {
650                         //
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));
655                 }
656                 //Next, get the Nick
657                 pszTempStr=strtok(szHackPrefix,"!");
658                 if(pszTempStr)
659                 {
660                         SDL_strlcpy(szNick, pszTempStr, sizeof(szNick));
661                 }
662                 else
663                 {
664                         SDL_strlcpy(szNick, szPrefix, sizeof(szNick));
665                 }
666                 //strcpy(NewMsg.Nickname,szNick);
667                 iNickLen=strlen(szNick);
668                 iPrefixLen=strlen(szPrefix);
669         }
670         else if(iMode==MSG_LOCAL)
671         {
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);
676                 iNickLen=-2;
677                 iPrefixLen=-2;
678         }
679         //Next is the command
680         pszTempStr=GetWordNum(0,szRemLine);
681         if(pszTempStr[0])
682         {
683                 SDL_strlcpy(szCmd, pszTempStr, sizeof(szCmd));
684         }
685         else
686         {
687                 //Shouldn't ever happen, but we can't be sure of what the host will send us.
688                 return NULL;
689         }
690
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)
696         {
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]==':')
701                 {
702                         SDL_strlcpy(szCTCPCmd, GetWordNum(0,szRemLine+1), sizeof(szCTCPCmd));
703                         if(szCTCPCmd[strlen(szCTCPCmd)-1]==0x01) szCTCPCmd[strlen(szCTCPCmd)-1]=0x00;
704
705                 }
706                 else
707                 {
708                         SDL_strlcpy(szCTCPCmd, GetWordNum(0,szRemLine), sizeof(szCTCPCmd));
709                         if(szCTCPCmd[strlen(szCTCPCmd)-1]==0x01) szCTCPCmd[strlen(szCTCPCmd)-1]=0x00;
710                 }
711                 if(szCTCPCmd[0]==0x01)
712                 {
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)
717                         {
718                                 //Posture
719                                 SDL_snprintf(szResponse, sizeof(szResponse), "* %s %s", szNick, szRemLine);
720                                 return szResponse;
721                         }
722                         if(iMode==MSG_LOCAL)
723                         {
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);
727                                 return szResponse;
728                         }
729                         if(SDL_strcasecmp(szCTCPCmd+1,NOX("PING"))==0)
730                         {
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);
733                                 return NULL;
734                         }
735                         if(SDL_strcasecmp(szCTCPCmd+1,NOX("VERSION"))==0)
736                         {
737                                 //reply with a notice version & copyright
738                                 //sprintf(szTempLine,"NOTICE %s :\001VERSION Copyright(c)\001\n",szNick);
739
740                                 return NULL;
741                         }
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);
745                         return szResponse;
746
747                 }
748                 //differentiate between channel and private
749                 if(szTarget[0]=='#')
750                 {
751                         pszTempStr=GetWordNum(0,szRemLine);
752                         SDL_snprintf(szResponse, sizeof(szResponse), "[%s] %s", szNick, pszTempStr);
753                         return szResponse;
754                 }
755                 else
756                 {
757                         if(iMode == MSG_LOCAL)
758                         {
759                                 pszTempStr=GetWordNum(0,szRemLine);
760                                 SDL_snprintf(szResponse, sizeof(szResponse), NOX("Private Message to <%s>: %s"), szNick, pszTempStr);
761                         }
762                         else
763                         {
764                                 pszTempStr=GetWordNum(0,szRemLine);
765                                 SDL_snprintf(szResponse, sizeof(szResponse), NOX("Private Message from <%s>: %s"), szNick, pszTempStr);
766                         }
767                         return szResponse;
768                 }
769
770         }
771         //don't handle any other messages locally.
772         if(iMode==MSG_LOCAL)
773         {
774                 return NULL;
775         }
776
777         if(SDL_strcasecmp(szCmd,NOX("NOTICE"))==0)
778         {
779                 
780
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]==':')
785                 {
786                         SDL_strlcpy(szCTCPCmd, GetWordNum(0,szRemLine+1), sizeof(szCTCPCmd));
787                         if(szCTCPCmd[strlen(szCTCPCmd)-1]==0x01) szCTCPCmd[strlen(szCTCPCmd)-1]=0x00;
788
789                 }
790                 else
791                 {
792                         SDL_strlcpy(szCTCPCmd, GetWordNum(0,szRemLine), sizeof(szCTCPCmd));
793                         if(szCTCPCmd[strlen(szCTCPCmd)-1]==0x01) szCTCPCmd[strlen(szCTCPCmd)-1]=0x00;
794                 }
795                 if(szCTCPCmd[0]==0x01)
796                 {
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)
801                         {
802                                 //This is a ping response, figure out time and print
803                                 //sprintf(NewMsg.Message,"** Ping Response from %s: %ums",szNick,ulping);
804                                 return NULL;
805                         }
806                         
807                         //Default message
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);
811                         return szResponse;
812                         
813                 }
814                 SDL_snprintf(szResponse, sizeof(szResponse), "%s", szRemLine);
815                 return NULL;
816         }
817         if(SDL_strcasecmp(szCmd,NOX("JOIN"))==0)
818         {
819                 //see if it is me!
820                 if(SDL_strcasecmp(Nick_name,szNick)==0)
821                 {
822                         //Yup, it's me!
823                         //if(strcmpi(szChat_channel,GetWordNum(0,szRemLine))==0)
824                         //{
825                                 Joined_channel = 1;
826                                 if(SDL_strcasecmp(szChat_channel,NOX("#autoselect"))==0)
827                                 {
828                                         SDL_strlcpy(szChat_channel, GetWordNum(0,szRemLine), sizeof(szChat_channel));
829                                         AddChatCommandToQueue(CC_YOURCHANNEL,szChat_channel,strlen(szChat_channel)+1);
830
831                                 }
832                                 //CC_YOURCHANNEL
833                         //}
834                 }
835                                 AddChatUser(szNick);
836
837                 
838                 pszTempStr=GetWordNum(0,szRemLine);
839                 SDL_strlcpy(szTarget, pszTempStr, sizeof(szTarget));
840                 //strcpy(szRemLine,Line+iPrefixLen+strlen(szCmd)+strlen(szTarget)+3);
841
842                 //strcpy(NewMsg.Channel,szTarget);
843
844                 AddChatUser(szNick);
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!
848         }
849         if(SDL_strcasecmp(szCmd,NOX("PART"))==0)
850         {
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));
854                 //see if it is me!
855                 if(SDL_strcasecmp(Nick_name,szNick)==0)
856                 {
857                         //Yup, it's me!
858                         //szChat_channel[0]=NULL;
859                         RemoveAllChatUsers();
860                 }
861                 
862                 RemoveChatUser(szNick);
863                 return NULL;
864                 //Remove them to the userlist too!
865         }
866         if(SDL_strcasecmp(szCmd,NOX("KICK"))==0)
867         {
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);
873                 //see if it is me!
874                 if(SDL_strcasecmp(Nick_name,GetWordNum(1,szRemLine))==0)
875                 {
876                         //Yup, it's me!
877                         szChat_channel[0]='\0';
878                         //bNewStatus=1;
879                         AddChatCommandToQueue(CC_KICKED,NULL,0);                        
880                         RemoveAllChatUsers();
881                 }
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);
885                 return szResponse;
886                 
887         }
888         if(SDL_strcasecmp(szCmd,NOX("NICK"))==0)
889         {
890       //see if it is me!
891                 if(SDL_strcasecmp(Nick_name,szNick)==0)
892                 {
893                         //Yup, it's me!
894                         SDL_strlcpy(Nick_name, GetWordNum(0,szRemLine), sizeof(Nick_name));
895                 }
896                 char nicks[70];
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));
902                 return szResponse;
903         }
904         if(SDL_strcasecmp(szCmd,NOX("PING"))==0)
905         {
906                 //respond with pong (GetWordNum(0,szRemLine))
907                 SDL_snprintf(szResponse, sizeof(szResponse), NOX("/PONG :%s"), GetWordNum(0,szRemLine));
908                 SendChatString(szResponse,1);
909                 return NULL;
910         }
911         if(SDL_strcasecmp(szCmd,NOX("MODE"))==0)
912         {
913                 //Channel Mode info
914                 return NULL;
915         }
916
917
918         if(SDL_strcasecmp(szCmd,"401")==0)
919         {
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;                         
925                                                 
926                 SDL_snprintf(szResponse, sizeof(szResponse), XSTR("**Error: %s is not online!",639), szWhoisUser);
927                 return szResponse;
928
929         }
930         if(SDL_strcasecmp(szCmd,"311")==0)
931         {
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)
936                 //{
937                         SDL_strlcpy(User_req_tracker_id, GetWordNum(5,szRemLine), sizeof(User_req_tracker_id));
938                 //}
939                 return NULL;
940         }
941         if(SDL_strcasecmp(szCmd,"319")==0)
942         {
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)
947                 //{
948                         SDL_strlcpy(User_req_channel, GetWordNum(2,szRemLine), sizeof(User_req_channel));
949                 //}
950                 return NULL;
951         }
952         
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)
955         {
956                 if(!*User_req_channel)
957                 {
958                         User_req_channel[0] = '*';
959                 }
960         }
961
962
963         if(SDL_strcasecmp(szCmd,"321")==0)
964         {
965                 //start of channel list
966                 FlushChannelList();
967                 GettingChannelList = 1;
968                 return NULL;
969         }
970         if(SDL_strcasecmp(szCmd,"322")==0)
971         {
972                 //channel list data
973                 if(GettingChannelList == 1)
974                 {
975                         char channel_list_name[33];
976                         char sztopic[200];
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);
980                 }
981                 return NULL;
982         }
983         if(SDL_strcasecmp(szCmd,"323")==0)
984         {
985                 //end of channel list
986                 GettingChannelList = 2;
987                 return NULL;
988         }
989         if(SDL_strcasecmp(szCmd,"324")==0)
990         {
991                 //Channel Mode info
992                 return NULL;
993         }
994
995         if(SDL_strcasecmp(szCmd,"332")==0)
996                 {
997                 //Channel Topic, update status bar.
998                 if(SDL_strcasecmp(szChat_channel,szTarget)==0)
999                 {
1000                         //strncpy(szChanTopic,GetWordNum(2,szRemLine),70);
1001                 }
1002                 //sprintf(NewMsg.Message,"*** %s has changed the topic to: %s",szNick,GetWordNum(2,szRemLine));
1003
1004                 return NULL;
1005         }
1006         if(SDL_strcasecmp(szCmd,NOX("TOPIC"))==0)
1007         {
1008                 //Channel Topic, update status bar.
1009                 if(SDL_strcasecmp(szChat_channel,szTarget)==0)
1010                 {
1011                         //strncpy(szChanTopic,GetWordNum(1,szRemLine),70);
1012                 }
1013                 //sprintf(NewMsg.Message,"*** %s has changed the topic to: %s",szNick,GetWordNum(1,szRemLine));
1014                 return NULL;
1015         }
1016         if(SDL_strcasecmp(szCmd,NOX("QUIT"))==0)
1017         {
1018                 //Remove the user!
1019                 RemoveChatUser(szNick);
1020                 return NULL;
1021         }
1022         if(SDL_strcasecmp(szCmd,"376")==0) //end of motd, trigger autojoin...
1023         {
1024                 if (!Chat_server_connected)
1025                 {
1026                         Chat_server_connected=1;
1027                 }
1028
1029                 // end of motd
1030                 SDL_strlcpy(szResponse, PXO_CHAT_END_OF_MOTD_PREFIX, sizeof(szResponse));
1031                 return szResponse;
1032         }
1033         if((SDL_strcasecmp(szCmd,"377")==0)||
1034                 (SDL_strcasecmp(szCmd,"372")==0)||
1035                 (SDL_strcasecmp(szCmd,"372")==0)
1036                 
1037                 )
1038         {
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));
1043                 return szResponse;
1044         }
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
1049                  /*
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) ||
1058                  */
1059
1060         {
1061                 return NULL;
1062         }
1063         if(SDL_strcasecmp(szCmd,"353")==0)
1064         {
1065
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," ");
1070
1071                 while(pszTempStr)
1072                 {
1073                         if(pszTempStr[0]=='@')
1074                         {
1075                                 AddChatUser(pszTempStr+1);
1076                         }
1077                         else if(pszTempStr[0]=='+')
1078                         {
1079                                 AddChatUser(pszTempStr+1);
1080                         }
1081                         else
1082                         {
1083                                 AddChatUser(pszTempStr);
1084                         }
1085                         pszTempStr=strtok(NULL," ");
1086                 }
1087                 return NULL;
1088         }
1089         //MOTD Codes
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)
1101            )
1102         {
1103                 // Stip the message, and display it.
1104                 // pszTempStr = GetWordNum(3, Line);
1105                 // strcpy(szResponse, PXO_CHAT_MOTD_PREFIX);
1106                 // strcat(szResponse, pszTempStr);
1107                 return NULL;
1108                 // return szResponse;
1109         }
1110         if(SDL_strcasecmp(szCmd,"432")==0)
1111         {
1112                 //Channel Mode info
1113                 SDL_strlcpy(szResponse, XSTR("Your nickname contains invalid characters",640), sizeof(szResponse));
1114                 AddChatCommandToQueue(CC_DISCONNECTED,NULL,0);
1115                 return szResponse;
1116         }
1117         if(SDL_strcasecmp(szCmd,"433")==0)
1118         {
1119                 //Channel Mode info
1120                 char new_nick[33];
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));
1123                 Nick_variety++;
1124                 SDL_snprintf(szResponse, sizeof(szResponse), NOX("/NICK %s"), new_nick);
1125                 SendChatString(szResponse,1);
1126                 return NULL;
1127         }
1128         //Default print
1129         SDL_strlcpy(szResponse, Line, sizeof(szResponse));
1130         //return szResponse;
1131         return NULL;
1132
1133 }
1134
1135
1136 void AddChatCommandToQueue(int command,const void *data,int len)
1137 {
1138         Currcommand = Firstcommand;
1139         if(Firstcommand==NULL)
1140         {
1141                 Firstcommand = (Chat_command *)malloc(sizeof(Chat_command));
1142                 SDL_assert(Firstcommand);
1143                 Firstcommand->next = NULL;
1144                 Currcommand = Firstcommand;
1145         }
1146         else
1147         {
1148                 while(Currcommand->next) 
1149                 {
1150                         Currcommand = Currcommand->next;
1151                 }
1152                 Currcommand->next = (Chat_command *)malloc(sizeof(Chat_command));
1153                 SDL_assert(Currcommand->next);
1154                 Currcommand = Currcommand->next;
1155         }
1156         Currcommand->command = (short)command;
1157         if(len&&data) memcpy(&Currcommand->data,data,len);
1158         Currcommand->next = NULL;
1159         return;
1160 }
1161
1162 Chat_command *GetChatCommandFromQueue(void)
1163 {
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;
1170         free(Firstcommand);
1171         Firstcommand = tmp_cmd;
1172         return &response_cmd;
1173 }
1174
1175 void FlushChatCommandQueue(void)
1176 {
1177         Chat_command *tmp_cmd;
1178         Currcommand = Firstcommand;
1179         
1180         while(Currcommand) 
1181         {
1182                 tmp_cmd = Currcommand->next;
1183                 free(Currcommand);
1184                 Currcommand = tmp_cmd;
1185         }
1186         Firstcommand = NULL;
1187 }
1188
1189
1190 void FlushChannelList(void)
1191 {
1192         Chat_channel *tmp_chan;
1193         Currchannel = Firstchannel;
1194         
1195         while(Currchannel) 
1196         {
1197                 tmp_chan = Currchannel->next;
1198                 free(Currchannel);
1199                 Currchannel = tmp_chan;
1200         }
1201         Firstchannel = NULL;
1202
1203
1204 }
1205 char *GetChannelList(void)
1206 {
1207         int ichan_list_length = 0;
1208         char sznumusers[10];
1209         
1210         if(GettingChannelList != 2) return NULL;
1211         if(!Socket_connected) return NULL;
1212
1213         if(Chan_list)
1214         {
1215                 free(Chan_list);
1216                 Chan_list = NULL;
1217         }
1218         
1219         
1220         Currchannel = Firstchannel;
1221         while(Currchannel) 
1222         {
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;
1225         }
1226         Currchannel = Firstchannel;
1227         Chan_list = (char *)malloc(ichan_list_length+1);
1228         Chan_list[0] = '\0';
1229         while(Currchannel) 
1230         {
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;
1239         }
1240         FlushChannelList();
1241         GettingChannelList = 0;
1242         return Chan_list;
1243 }
1244
1245 void AddChannel(char *channel,unsigned short numusers,char *topic)
1246 {
1247         Currchannel = Firstchannel;
1248         if(Firstchannel==NULL)
1249         {
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;
1257         }
1258         else
1259         {
1260                 while(Currchannel->next) 
1261                 {
1262                         Currchannel = Currchannel->next;
1263                 }
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;
1270         }
1271         Currchannel->next = NULL;
1272         return;
1273 }
1274
1275
1276 char *GetTrackerIdByUser(char *nickname)
1277 {
1278         char szWhoisCmd[100];
1279
1280         
1281         if(GettingUserTID)
1282         {
1283                 if(Getting_user_tracker_error)
1284                 {
1285                         Getting_user_tracker_error = 0;
1286                         GettingUserTID = 0;
1287                         return (char *)-1;
1288                 }
1289                 
1290                 if(*User_req_tracker_id)
1291                 {
1292                         GettingUserTID = 0;
1293                         return User_req_tracker_id;
1294                 }
1295         }
1296         else
1297         {
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);           
1302                 GettingUserTID = 1;
1303         }
1304         return NULL;
1305 }
1306
1307 char *GetChannelByUser(char *nickname)
1308 {
1309         char szWhoisCmd[100];
1310         
1311         if(GettingUserChannel)
1312         {
1313                 if(Getting_user_channel_error)
1314                 {
1315                         Getting_user_channel_error = 0;
1316                         GettingUserChannel = 0;
1317                         return (char *)-1;
1318                 }
1319                 if(*User_req_channel)
1320                 {
1321                         GettingUserChannel = 0;
1322                         return User_req_channel;
1323                 }
1324         }
1325         else
1326         {
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;
1332         }
1333         return NULL;
1334 }
1335