/* * Code from: Philipp Meinen * Copyright (C): 2003-2004 Philipp Meinen * * Email: lancelot@lancelot2k.dyndns.org * Homepage: http://lancelot2k.dyndns.org * License: GPL * */ #define _SERVER_CC_ #include #include #include #include #include #include #include #include #include #include #include #include #include "server.h" Server::Server(void) { connect_status = STATUS_NOTHING; cs_printed = 0; maybe_reconnect = 0; do_connect = 0; socketfd = -1; memset(&socket_data, '\0', sizeof(struct sockaddr)); help_buffer[0] = '\0'; normal_text[0] = '\0'; OneInputLine[0] = '\0'; InputData[0] = '\0'; last_ping = 0; StartCommandsSent = 0; LastCommandTime = time(NULL)+2; Num_InputParameters = 0; ModesSet = 0; InputParameters = new char * [NUM_INPUTPARAMETERS_MAX]; for(int i = 0; i < NUM_INPUTPARAMETERS_MAX; i++) InputParameters[i] = NULL; return; } Server::~Server(void) { return; } void Server::Connect(void) { if(do_connect) Disconnect(); /* clean up if we have to connect */ do_connect = 0; if(connect_status == STATUS_NOTHING) { SetConnectStatus(STATUS_RESOLV_IN_PROGRESS); if(pthread_create(&nameresolver, NULL, nameresolv_wrapper, (void *)this) != 0) { /* create thread error */ SetConnectStatus(STATUS_NOTHING); int screen_nr = Classes.IrcScreen->GetActiveChannel(); Classes.MsgDB->SetIrcChatMessage(screen_nr, DISPLAY_ERROR, MESSAGE_ERR_PTHREAD); if(screen_nr) Classes.MsgDB->SetIrcChatMessage(0, DISPLAY_ERROR, MESSAGE_ERR_PTHREAD); Classes.IrcScreen->DrawTextScreen(); } } else if(connect_status == STATUS_RESOLV_IN_PROGRESS) { /* name resolving still in progress */ return; } else if(connect_status == STATUS_RESOLVING_FINISHED) { maybe_reconnect = 1; /* Get a socket */ snprintf(help_buffer, HELP_BUF_LEN, "Connecting to %s:%i ...", servername, port); Classes.MsgDB->SetIrcChatMessage(0, DISPLAY_AUTHINFO, help_buffer); Classes.IrcScreen->DrawTextScreen(); socketfd = socket(PF_INET, SOCK_STREAM, 0); if(socketfd == -1) { SetConnectStatus(STATUS_NOTHING); return; } fcntl(socketfd, F_SETFL, O_NONBLOCK); /* the socket should be non-blocking */ /* and now connect */ SetConnectStatus(STATUS_SYN_SENT); connect(socketfd, (struct sockaddr *)&socket_data, sizeof(socket_data)); } return; } void Server::Disconnect(void) { if(socketfd && connect_status > STATUS_SYN_SENT) Classes.MsgDB->SetIrcChatMessage(0, DISPLAY_SERVERMSG, MESSAGE_DISCONNECT); if(socketfd != -1) close(socketfd); socketfd = -1; ResetParameters(); Classes.IrcScreen->EmptyAllScreens(); Classes.IrcUserDB->Reset_All_UserDB(); Classes.IrcScreen->DrawTextScreen(); Classes.IrcScreen->DrawBottomScreen(); Classes.IrcScreen->DrawTopScreen(); return; } void Server::GetHostname(void) { SetConnectStatus(STATUS_RESOLV_IN_PROGRESS); SetServername(Classes.IrcUser->GetServername()); SetServerport(Classes.IrcUser->GetPort()); snprintf(help_buffer, HELP_BUF_LEN, "%s%s ...", MESSAGE_HOST_LOOKUP, servername); Classes.MsgDB->SetIrcChatMessage(0, DISPLAY_AUTHINFO, help_buffer); Classes.IrcScreen->DrawTextScreen(); struct hostent * serverparams = NULL; /* fill the socket_data structure whith values */ if(inet_aton(servername, &socket_data.sin_addr) == 0) { serverparams = gethostbyname(servername); if(serverparams == NULL) { Classes.MsgDB->SetIrcChatMessage(0, DISPLAY_ERROR, MESSAGE_HOST_NOTFOUND); Classes.IrcScreen->DrawTextScreen(); SetConnectStatus(STATUS_NOTHING); pthread_exit(NULL); } memcpy(&socket_data.sin_addr.s_addr, serverparams->h_addr, serverparams->h_length); } socket_data.sin_port = htons(port); socket_data.sin_family = AF_INET; Classes.MsgDB->SetIrcChatMessage(0, DISPLAY_AUTHINFO, MESSAGE_HOST_LOOKUP_OK); Classes.IrcScreen->DrawTextScreen(); SetConnectStatus(STATUS_RESOLVING_FINISHED); pthread_exit(NULL); /* never reached */ return; } int Server::SetServername(char * new_servername) { if(new_servername == NULL) return 0; if(new_servername[0] == '\0') return 0; if(strlen(new_servername) >= SERVER_NAME_LEN) return 0; /* to long */ strncpy(servername, new_servername, SERVER_NAME_LEN-1); return 1; /* OK */ } int Server::SetServerport(int new_port) { if((new_port < 1) || (new_port > 65535)) return 0; /* port out of range */ port = new_port; return 1; /* OK */ } char * Server::GetServername(void) { return servername; } int Server::GetServerport(void) { return port; } int Server::GetInput(void) { int had_input = 1; int read_num = 0; int newlen = 0; int oldlen = strlen(InputData); int max_read_len = INPUT_BUFFER_LEN - oldlen - 1; char tmp_buf[max_read_len+1]; read_num = recv(socketfd, tmp_buf, max_read_len, 0); if(read_num == 0) had_input = 0; /* connection was closed by server */ if(read_num == -1) { /* there was an error */ had_input = 0; if(errno == ENOTCONN) { /* the socket is not connected */ Disconnect(); } } if(read_num > max_read_len) had_input = 0; /* wtf? */ if(had_input == 1) { tmp_buf[read_num] = '\0'; newlen = oldlen + read_num; memcpy(InputData+oldlen, tmp_buf, read_num); InputData[newlen] = '\0'; ParseInput(); } return had_input; } void Server::ParseInput(void) { do { parsing_finished = 0; int atnum = 0; /* irc-answer-type-nr */ /* main loop of server input parsing */ ReadOneLineFromInput(); if(OneInputLine[0] == '\0') return; #ifdef DEBUG fprintf(stderr, "FromServer <--- \"%s\"\n", OneInputLine); fflush(stderr); #endif Bring_away_special_chars(OneInputLine); Read_InputParameters(); atnum = GetAnswerTypeNr(); if(atnum && Check_InputData(atnum)) { /* We have a Answertypenumber */ if(atnum >= 1 && atnum <= 9) { SetConnectStatus(STATUS_MAX_NUM); cs_printed = 1; PrintNormalText(DISPLAY_SERVERMSG); } else if(atnum == 221) ParseCommand_221(); else if(atnum >= 250 && atnum <= 255) PrintNormalText(DISPLAY_SERVERMSG); else if(atnum == 265) ParseCommand_265(); else if(atnum == 266) ParseCommand_266(); else if(atnum == 267) ParseCommand_267(); else if(atnum == 315) ParseCommand_315(); else if(atnum == 318) ParseCommand_318(); else if(atnum == 324) ParseCommand_324(); else if(atnum == 329) ParseCommand_329(); else if(atnum == 331) ParseCommand_331(); else if(atnum == 332) ParseCommand_332(); else if(atnum == 333) ParseCommand_333(); else if(atnum == 353) ParseCommand_353(); else if(atnum == 366) ParseCommand_366(); else if(atnum == 372) ParseCommand_372(); else if(atnum == 375) ParseCommand_375(); else if(atnum == 376) ParseCommand_376(); else if(atnum == 401) ParseCommand_401(); else if(atnum == 403) ParseCommand_403(); else if(atnum == 421) ParseCommand_421(); else if(atnum == 433) ParseCommand_433(); else if(atnum == 451) ParseCommand_451(); else if(atnum == 461) ParseCommand_461(); else if(atnum == 473) ParseCommand_473(); else if(atnum == 474) ParseCommand_474(); else if(atnum == 475) ParseCommand_475(); else if(atnum == 502) ParseCommand_502(); else if(atnum == PROTOCOL_NUM_PONG ) ParseCommand_PONG(); else if(atnum == PROTOCOL_NUM_PRIVMSG ) ParseCommand_PRIVMSG(); else if(atnum == PROTOCOL_NUM_NOTICE ) ParseCommand_NOTICE(); else if(atnum == PROTOCOL_NUM_JOIN ) ParseCommand_JOIN(); else if(atnum == PROTOCOL_NUM_PART ) ParseCommand_PART(); else if(atnum == PROTOCOL_NUM_QUIT ) ParseCommand_QUIT(); else if(atnum == PROTOCOL_NUM_NICK ) ParseCommand_NICK(); else if(atnum == PROTOCOL_NUM_MODE ) ParseCommand_MODE(); else if(atnum == PROTOCOL_NUM_KICK ) ParseCommand_KICK(); else if(atnum == PROTOCOL_NUM_TOPIC ) ParseCommand_TOPIC(); else if(atnum == PROTOCOL_NUM_PING ) ParseCommand_PING(); else if(atnum == PROTOCOL_NUM_WALLOPS ) ParseCommand_WALLOPS(); else if(atnum == PROTOCOL_NUM_SERVERNOTICE) ParseCommand_SERVERNOTICE(); else { /* if we do not know the command: just print it */ snprintf(help_buffer, HELP_BUF_LEN, "not implemented: %s", OneInputLine); Classes.MsgDB->SetIrcChatMessage(0, DISPLAY_NOTIMPLEMENTED, help_buffer); Parsing_Finished(); } } else { /* there is no type number for this message * raw text will be simply printed on the infoscreen */ Classes.MsgDB->SetIrcChatMessage(0, DISPLAY_RAWTEXT, OneInputLine); Parsing_Finished(); } if(!parsing_finished) { /* one of the parsing functions failed */ Classes.MsgDB->SetIrcChatMessage(0, DISPLAY_NOTPARSED, OneInputLine); } Cleanup_InputParameters(); } while(InputData[0] != '\0'); Classes.IrcScreen->DrawTextScreen(); Classes.IrcScreen->DrawBottomScreen(); return; } void Server::Read_InputParameters(void) { /* clean the existing parameters before reading the new ones */ if(Num_InputParameters != 0) Cleanup_InputParameters(); int start_position = 0, end_position = 0; int param_len; int len = strlen(OneInputLine); do { if(Num_InputParameters == NUM_INPUTPARAMETERS_MAX) break; if(Num_InputParameters != 0) { /* we allready have parameters */ start_position = end_position; } end_position = search_next_num_char(OneInputLine, ' ', 1, end_position+1); if(end_position != -1) { while(OneInputLine[end_position+1] == ' ') { end_position++; } } if(end_position != -1) { /* this is not the last Parameter */ if(Num_InputParameters != 0) { param_len = (end_position - start_position) - 1; } else { param_len = end_position - start_position; } } else { /* this is the last parameter */ param_len = (len - start_position) - 1; } if(Num_InputParameters != 0) start_position++; /* add one if we are not on the begining (so we dont take the space) */ if(start_position >= len) break; InputParameters[Num_InputParameters] = new char[param_len+1]; if(param_len > 0) memcpy(InputParameters[Num_InputParameters], OneInputLine+start_position, param_len); InputParameters[Num_InputParameters][param_len] = '\0'; Num_InputParameters++; } while(end_position != -1); return; } void Server::Cleanup_InputParameters(void) { while(Num_InputParameters > 0) { if(InputParameters[Num_InputParameters-1] != NULL) { delete[] InputParameters[Num_InputParameters-1]; InputParameters[Num_InputParameters-1] = NULL; } Num_InputParameters--; } return; } int Server::Check_InputData(int atnum) { if(atnum < 1 || atnum > PROTOCOL_HIGHEST_NUMBER) return 0; if(!input_params[atnum].defined) return 0; if(Num_InputParameters < input_params[atnum].parameters_min) return 0; if(Num_InputParameters > input_params[atnum].parameters_max) return 0; return 1; } int Server::Check_Parameter_for_space(int parameter_nr) { char *x = &InputParameters[parameter_nr][0]; while(*x) { if(*x == ' ') return 1; x++; } return 0; } void Server::Put_Text_together(int startposition) { normal_text[0] = '\0'; int num_params = Num_InputParameters - startposition; if(num_params < 1) return; strncpy(normal_text, InputParameters[startposition], HELP_BUF_LEN-1); int rest_len; for(int i = 1; i < num_params; i++) { rest_len = HELP_BUF_LEN - (strlen(normal_text) + 1); if(rest_len < 2) return; strncat(normal_text, " ", 1); strncat(normal_text, InputParameters[startposition+i], (rest_len-1)); } /* If there is a ':' we can Ignore it! */ if(normal_text[0] == ':') { make_first_char_away(normal_text); } return; } void Server::ReadOneLineFromInput(void) { OneInputLine[0] = '\0'; if(InputData[0] == '\0') return; /* return when there is anyway no data */ int len = (signed)strlen(InputData); int position = 0; /* find the position where '\n' can be found */ position = position_of_num_char(InputData, '\n', 1); if(position == -1) return; /* there is no new message is available */ if(position < 1) return; /* there is not a single char of message */ if(position >= ONELINE_READ_MAXLEN - 1) position = ONELINE_READ_MAXLEN - 2; memcpy(OneInputLine, InputData, position); /* I dont want a "\r\n" ond the end */ if(InputData[position-1] == '\r') { OneInputLine[position - 1] = '\0'; } else { OneInputLine[position] = '\0'; } /* also I dont want a '\r' in the hole input string */ int i; for(i = 0; i < position; i++) if(OneInputLine[i] == '\r') OneInputLine[i] = ' '; int rest_len = (len - position) - 1; /* not I move the rest over the input-data on the begining of the string */ for(i = 0; i < rest_len; i++) { InputData[i] = InputData[i+position+1]; } InputData[rest_len] = '\0'; return; } int Server::WriteMessageToServer(char * new_message) { if(connect_status < STATUS_CONNECTED) return 0; int ret = -1, len = 0; len = strlen(new_message); if(len <= 0) return 0; /* check for \r\n at the end of the data */ #ifdef DEBUG fprintf(stderr, "ToServer ---> \"%s\"\n", new_message); fflush(stderr); #endif if((new_message[len-1] != '\n') || (new_message[len-2] != '\r')) { /* end of new_message is not \r\n */ char send_buf[len+3]; memcpy(send_buf, new_message, len); send_buf[len] = '\r'; send_buf[len+1] = '\n'; send_buf[len+2] = '\0'; ret = write(socketfd, send_buf, len+2); } else ret = write(socketfd, new_message, len); if(ret == -1) { Disconnect(); if(Classes.IrcUser->GetAutoReconnect()) do_connect = 1; else do_connect = 0; if(errno == ECONNABORTED) { /* connection aborted */ Classes.MsgDB->SetIrcChatMessage(0, DISPLAY_SERVERMSG, MESSAGE_ABORTED); } else if(errno == ECONNREFUSED) { /* connection refused */ Classes.MsgDB->SetIrcChatMessage(0, DISPLAY_SERVERMSG, MESSAGE_REFUSED); } else if(errno == ECONNRESET) { /* connection reset */ Classes.MsgDB->SetIrcChatMessage(0, DISPLAY_SERVERMSG, MESSAGE_RESET); } else { /* another error */ char * connect_error = strerror(errno); snprintf(help_buffer, HELP_BUF_LEN, "Connection closed because of error \"%s\", please report this error to bugs@lancelot2k.dyndnsn.org", connect_error); Classes.MsgDB->SetIrcChatMessage(0, DISPLAY_ERROR, help_buffer); } } else { if(!cs_printed) { cs_printed = 1; Classes.MsgDB->SetIrcChatMessage(0, DISPLAY_AUTHINFO, MESSAGE_CONNECTED); } } Classes.IrcScreen->DrawTextScreen(); return 1; /* OK */ } int Server::GetAnswerTypeNr(void) { if(Num_InputParameters <= 1) return 0; /* to less parameters */ if(Num_InputParameters == 2) { /* the message has only 2 parts */ if(Check_Parameter_for_space(0) || Check_Parameter_for_space(1)) return 0; if(strcmp(InputParameters[0], "PING") == 0) return PROTOCOL_NUM_PING; return 0; } if(strcmp(InputParameters[0], "NOTICE") == 0) return PROTOCOL_NUM_SERVERNOTICE; if(Num_InputParameters < 3) return 0; /* to less parameters */ if(Check_Parameter_for_space(0) || Check_Parameter_for_space(1)) return 0; if(InputParameters[0][0] != ':') return 0; /* if the very first character is no dblpoint it is to be seen as a raw message */ int len = strlen(&InputParameters[1][0]); /* Check the text for commands */ if(len == 3) { /* we possibly have a numeric command */ return atoi(InputParameters[1]); } else if(len == 4) { if(strcmp(InputParameters[1], "PONG") == 0) return PROTOCOL_NUM_PONG; if(strcmp(InputParameters[1], "JOIN") == 0) return PROTOCOL_NUM_JOIN; if(strcmp(InputParameters[1], "PART") == 0) return PROTOCOL_NUM_PART; if(strcmp(InputParameters[1], "QUIT") == 0) return PROTOCOL_NUM_QUIT; if(strcmp(InputParameters[1], "NICK") == 0) return PROTOCOL_NUM_NICK; if(strcmp(InputParameters[1], "MODE") == 0) return PROTOCOL_NUM_MODE; if(strcmp(InputParameters[1], "KICK") == 0) return PROTOCOL_NUM_KICK; } else if(len == 5) { if(strcmp(InputParameters[1], "TOPIC") == 0) return PROTOCOL_NUM_TOPIC; } else if(len == 6) { if(strcmp(InputParameters[1], "NOTICE") == 0) return PROTOCOL_NUM_NOTICE; } else if(len == 7) { if(strcmp(InputParameters[1], "PRIVMSG") == 0) return PROTOCOL_NUM_PRIVMSG; if(strcmp(InputParameters[1], "WALLOPS") == 0) return PROTOCOL_NUM_WALLOPS; } return 0; } void Server::LoginToServer(void) { /* RFC 2812 entry about the USER command: * Command: USER * Parameters: * * The USER command is used at the beginning of connection to specify * the username, hostname and realname of a new user. * The parameter should be a numeric, and can be used to * automatically set user modes when registering with the server. This * parameter is a bitmask, with only 2 bits having any signification: if * the bit 2 is set, the user mode 'w' will be set and if the bit 3 is * set, the user mode 'i' will be set. (See Section 3.1.5 "User * Modes"). * * The may contain space characters. * * Numeric Replies: * ERR_NEEDMOREPARAMS ERR_ALREADYREGISTRED * Example: * * USER guest 0 * :Ronnie Reagan ; User registering themselves with a * username of "guest" and real name * "Ronnie Reagan". * * USER guest 8 * :Ronnie Reagan ; User registering themselves with a * username of "guest" and real name * "Ronnie Reagan", and asking to be set * invisible. * * * and here some nice things from rfc 1459 * A "PASS" command is not required for either client or server * connection to be registered, but it must precede the server message * or the latter of the NICK/USER combination. It is strongly * recommended that all server connections have a password in order to * give some level of security to the actual connections. The * recommended order for a client to register is as follows: * * 1. Pass message * 2. Nick message * 3. User message * now make our user command */ if(connect_status != STATUS_CONNECTED) return; /* try to set the nickname */ snprintf(help_buffer, HELP_BUF_LEN, "NICK %s", Classes.IrcUser->GetNickname()); WriteMessageToServer(help_buffer); // char * username = getenv("USER");; // if(username != NULL) { // if(username[0] == '\0') username = Classes.IrcUser->GetNickname(); // } else username = Classes.IrcUser->GetNickname(); snprintf(help_buffer, HELP_BUF_LEN, "USER netwalker 0 * :%s", Classes.IrcUser->GetRealname()); WriteMessageToServer(help_buffer); connect_status = STATUS_LOGIN_TRIED; return; } void Server::ParseCommand_221(void) { /* :network 221 + */ if(InputParameters[3][0] != '+') return; /* false format ? I have to check this! */ snprintf(help_buffer, HELP_BUF_LEN, "modes for user %s: %s", InputParameters[2], InputParameters[3]); int screen_nr = Classes.IrcScreen->GetActiveChannel(); Classes.MsgDB->SetIrcChatMessage(screen_nr, DISPLAY_MODE, help_buffer); Parsing_Finished(); return; } void Server::ParseCommand_265(void) { PrintNormalText(DISPLAY_SERVERMSG); return; } void Server::ParseCommand_266(void) { PrintNormalText(DISPLAY_SERVERMSG); return; } void Server::ParseCommand_267(void) { PrintNormalText(DISPLAY_SERVERMSG); return; } void Server::ParseCommand_315(void) { /* we can safely ignore this */ Parsing_Finished(); return; } void Server::ParseCommand_318(void) { /* we can safely ignore this */ Parsing_Finished(); return; } void Server::ParseCommand_324(void) { /* :network 324 #channel + [parameter1] [parameter2] [...] */ char tmp_channelname[CHANNELS_NAME_LEN]; GetChannelName(tmp_channelname, 3, CHANNELS_NAME_LEN); if(tmp_channelname[0] == '\0') return; /* false format */ int screen_nr = Classes.IrcScreen->GetScreenNr(tmp_channelname, 0); Put_Text_together(3); snprintf(help_buffer, HELP_BUF_LEN, "Modes for #%s: %s", tmp_channelname, normal_text); Classes.MsgDB->SetIrcChatMessage(screen_nr, DISPLAY_MODE, help_buffer); Parsing_Finished(); return; } void Server::ParseCommand_329(void) { /* :network 329 #channel */ char tmp_channelname[CHANNELS_NAME_LEN]; GetChannelName(tmp_channelname, 3, CHANNELS_NAME_LEN); if(tmp_channelname[0] == '\0') return; /* false format */ int screen_nr = Classes.IrcScreen->GetScreenNr(tmp_channelname, 0); if((signed)strlen(InputParameters[4]) < 9) return; /* this cant be a unix-timestamp, or the channel has been created a veeeery long time ago :) (actual timestamp len: 10) */ time_t timestamp = atoi(InputParameters[4]); if(!timestamp) return; /* this were not only numbers */ struct tm time_info; localtime_r(×tamp, &time_info); snprintf(help_buffer, HELP_BUF_LEN, "This Channel has been built on %i.%i.%i - %.2i:%.2i", time_info.tm_mday, time_info.tm_mon, (time_info.tm_year + 1900), time_info.tm_hour, time_info.tm_min); Classes.MsgDB->SetIrcChatMessage(screen_nr, DISPLAY_DEFAULT, help_buffer); Parsing_Finished(); return; } void Server::ParseCommand_331(void) { /* :server 331 your_nickname #channel :No topic is set. */ int screen_nr = Classes.IrcScreen->GetScreenNumForChannel(InputParameters[3]+1); if(!screen_nr) return; /* illegal command */ snprintf(help_buffer, HELP_BUF_LEN, "no topic is set for this channel"); Classes.MsgDB->SetIrcChatMessage(screen_nr, DISPLAY_TOPIC, help_buffer); Parsing_Finished(); return; } void Server::ParseCommand_332(void) { TopicHandler(0); return; } void Server::ParseCommand_333(void) { /* :network 333 #channel */ char tmp_channelname[CHANNELS_NAME_LEN]; GetChannelName(tmp_channelname, 3, CHANNELS_NAME_LEN); if(tmp_channelname[0] == '\0') return; /* false format */ int screen_nr = Classes.IrcScreen->GetScreenNr(tmp_channelname, 0); if(!screen_nr) return; /* no such channel */ time_t timestamp = atoi(InputParameters[5]); if(!timestamp) { /* this were not only numbers */ snprintf(help_buffer, HELP_BUF_LEN, "Topic set by %s", InputParameters[4]); } else { struct tm time_settings; localtime_r(×tamp, &time_settings); snprintf(help_buffer, HELP_BUF_LEN, "Topic set by %s on %i.%i.%i - %.2i:%.2i", InputParameters[4], time_settings.tm_mday, time_settings.tm_mon, (time_settings.tm_year + 1900), time_settings.tm_hour, time_settings.tm_min); } Classes.MsgDB->SetIrcChatMessage(screen_nr, DISPLAY_TOPIC, help_buffer); Parsing_Finished(); return; } void Server::ParseCommand_353(void) { /* :network 353 (= or * or @) #channel :[@ or +] [[[@ or +]]] [[[@ or +]]] */ if((signed)strlen(InputParameters[3]) != 1) return; /* false format */ if((InputParameters[3][0] != '=') && (InputParameters[3][0] != '*') && (InputParameters[3][0] != '@')) return; /* false format */ char tmp_channelname[CHANNELS_NAME_LEN]; GetChannelName(tmp_channelname, 4, CHANNELS_NAME_LEN); if(tmp_channelname[0] == '\0') return; /* false format */ if(InputParameters[5][0] != ':') return; /* false format */ /* make the ':' away */ make_first_char_away(InputParameters[5]); int num_names = Num_InputParameters - 5; for(int i = 0; i < num_names; i++) { if(InputParameters[5+i][0] == '@' || InputParameters[5+i][0] == '+') make_first_char_away(InputParameters[5+i]); if(InputParameters[5+i][0] != '\0') { Classes.IrcUserDB->Add_User(InputParameters[5+i], tmp_channelname); } } Classes.IrcScreen->DrawBottomScreen(); Parsing_Finished(); return; } void Server::ParseCommand_366(void) { /* I dont have anything to do when I receive such a command. * The reason is, that I simply add the usernames (commands: JOIN and 353) if they are not not in the database */ Parsing_Finished(); return; } void Server::ParseCommand_372(void) { PrintNormalText(DISPLAY_SERVERMSG); return; } void Server::ParseCommand_375(void) { PrintNormalText(DISPLAY_SERVERMSG); return; } void Server::ParseCommand_376(void) { PrintNormalText(DISPLAY_SERVERMSG); return; } void Server::ParseCommand_401(void) { /* :server 401 your_nickname #channel :No such nick/channel * :server 401 your_nickanem other_nickname :No such nick/channel*/ if(InputParameters[3][0] == '#') { /* this is because of a channel */ snprintf(help_buffer, HELP_BUF_LEN, "No such channel: %s", InputParameters[3]); } else { /* this is because of a nickname */ snprintf(help_buffer, HELP_BUF_LEN, "No such nickname: %s", InputParameters[3]); } int active_channel = Classes.IrcScreen->GetActiveChannel(); Classes.MsgDB->SetIrcChatMessage(active_channel, DISPLAY_ERROR, help_buffer); Parsing_Finished(); return; } void Server::ParseCommand_403(void) { /* :server 403 your_nickname #channel :That channel doesn't exist */ snprintf(help_buffer, HELP_BUF_LEN, "That channel doesn't exist: %s", InputParameters[3]); int active_channel = Classes.IrcScreen->GetActiveChannel(); Classes.MsgDB->SetIrcChatMessage(active_channel, DISPLAY_ERROR, help_buffer); Parsing_Finished(); return; } void Server::ParseCommand_421(void) { /* :server 421 your_nickname command :Unknown command */ snprintf(help_buffer, HELP_BUF_LEN, "Unknown command: %s", InputParameters[3]); int active_channel = Classes.IrcScreen->GetActiveChannel(); Classes.MsgDB->SetIrcChatMessage(active_channel, DISPLAY_ERROR, help_buffer); Parsing_Finished(); return; } void Server::ParseCommand_433(void) { int screen_nr = Classes.IrcScreen->GetActiveChannel(); if(STATUS_ALL_OK != 1) { /* we are not successfully logged in * lets add a '_' to the nickname and try it again */ snprintf(help_buffer, HELP_BUF_LEN, "%s_", Classes.IrcUser->GetNickname()); if(strlen(help_buffer) > NICKNAME_LEN - 1) help_buffer[NICKNAME_LEN/2] = '\0'; Classes.IrcUser->SetNickname(help_buffer); snprintf(help_buffer, HELP_BUF_LEN, "NICK %s", Classes.IrcUser->GetNickname()); WriteMessageToServer(help_buffer); snprintf(help_buffer, HELP_BUF_LEN, "Nickname allready in use, retrying with %s", Classes.IrcUser->GetNickname()); Classes.MsgDB->SetIrcChatMessage(screen_nr, DISPLAY_ERROR, help_buffer); } else Classes.MsgDB->SetIrcChatMessage(screen_nr, DISPLAY_ERROR, "Nickname allready in use."); Parsing_Finished(); return; } void Server::ParseCommand_451(void) { /* blub, and what now? :) * the messages will be repeatet anyway, so I can ignore that. */ Parsing_Finished(); return; } void Server::ParseCommand_461(void) { /* :server 461 your_nickname MODE :Not enough parameters */ snprintf(help_buffer, HELP_BUF_LEN, "not enough parameters for command: %s", InputParameters[3]); int active_channel = Classes.IrcScreen->GetActiveChannel(); Classes.MsgDB->SetIrcChatMessage(active_channel, DISPLAY_ERROR, help_buffer); Parsing_Finished(); return; } void Server::ParseCommand_473(void) { /* :server 473 your_nickname #channel :Cannot join channel (+i) */ snprintf(help_buffer, HELP_BUF_LEN, "you cannot join the channel %s because this channel is invite only!", InputParameters[3]); int active_channel = Classes.IrcScreen->GetActiveChannel(); Classes.MsgDB->SetIrcChatMessage(active_channel, DISPLAY_ERROR, help_buffer); Parsing_Finished(); return; } void Server::ParseCommand_474(void) { /* :server 474 your_nickname #channel :Cannot join channel (+b) */ snprintf(help_buffer, HELP_BUF_LEN, "you cannot join the channel %s because you are banned from this server!", InputParameters[3]); int active_channel = Classes.IrcScreen->GetActiveChannel(); Classes.MsgDB->SetIrcChatMessage(active_channel, DISPLAY_ERROR, help_buffer); Parsing_Finished(); return; } void Server::ParseCommand_475(void) { /* :server 475 your_nickname #channel :Cannot join channel (+k) */ snprintf(help_buffer, HELP_BUF_LEN, "you cannot join the channel %s because this channel is password protected! (use /join %s password)", InputParameters[3], InputParameters[3]); int active_channel = Classes.IrcScreen->GetActiveChannel(); Classes.MsgDB->SetIrcChatMessage(active_channel, DISPLAY_ERROR, help_buffer); Parsing_Finished(); return; } void Server::ParseCommand_502(void) { /* :network 502 : */ int screen_nr = Classes.IrcScreen->GetActiveChannel(); Classes.MsgDB->SetIrcChatMessage(screen_nr, DISPLAY_ERROR, "You can't change someone else's modes"); Parsing_Finished(); return; } void Server::ParseCommand_PONG(void) { /* perhaps I'll later write some code to check the delay between * PING and PONG */ Parsing_Finished(); return; } void Server::ParseCommand_PRIVMSG(void) { /* here some examples for /me or ctcp * +----+----+----+----+----+----+----+----+----+----+----+ * | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | * +----+----+----+----+----+----+----+----+----+----+----+ * | \1 | A | C | T | I | O | N | | A | \1 | \0 | * +----+----+----+----+----+----+----+----+----+----+----+ * | \1 | V | E | R | S | I | O | N | \1 | \0 | | * +----+----+----+----+----+----+----+----+----+----+----+ * */ char nickname[NICKNAME_LEN]; GetSenderName(nickname, 0, NICKNAME_LEN); if(nickname[0] == '\0') return; /* false format */ Put_Text_together(3); int slashme = 0; int actionmsg = 0; int len = strlen(normal_text); if(len >= 3) { if((normal_text[0] == 1) && (normal_text[len-1] == 1)) { normal_text[len-1] = '\0'; actionmsg = 1; if((len >= 10) && (strncmp(normal_text+1, "ACTION ", 7) == 0)) { slashme = 1; snprintf(help_buffer, HELP_BUF_LEN, "%s %s", nickname, normal_text+8); } } } /* is there a # after the PRIVMSG? when yes: this message is for a channel */ if(InputParameters[2][0] == '#') { /* OK, this is for a channel */ char channelname[CHANNELS_NAME_LEN]; GetChannelName(channelname, 2, CHANNELS_NAME_LEN); if(channelname[0] == '\0') return; /* false format */ int screen = Classes.IrcScreen->GetScreenNr(channelname, 0); if(slashme) { Classes.MsgDB->SetIrcChatMessage(screen, DISPLAY_MEACTION, help_buffer); } else { Classes.MsgDB->SetIrcChatMessage(screen, nickname, normal_text); } } else { int screen = Classes.IrcScreen->GetScreenNr(nickname, 1); if(!screen) { /* there was no screen found for this message, get a new one */ screen = Classes.IrcScreen->GetNotUsedScreen(1); if(!screen) return; /* no screen left */ Classes.IrcScreen->SetDirectChatNick(screen, nickname); Classes.IrcScreen->SetActiveChannel(screen); /* we change to this screen because it is the inital message */ } /* It seems to be a direct chat message but it could also be a CTCP message! * so I first check if it is a CTCP message */ if((actionmsg) && (!slashme)) { snprintf(help_buffer, HELP_BUF_LEN, "%s", normal_text+1); string_toupper(help_buffer); if(strcmp(help_buffer, "VERSION") == 0) { snprintf(normal_text, HELP_BUF_LEN, "received a CTCP %s from %s", help_buffer, nickname); snprintf(help_buffer, HELP_BUF_LEN, "NOTICE %s :\1VERSION %s\1", nickname, CTCP_VERSION_REPLY); WriteMessageToServer(help_buffer); } else { snprintf(normal_text, HELP_BUF_LEN, "received a CTCP %s from %s", help_buffer, nickname); } Classes.MsgDB->SetIrcChatMessage(screen, DISPLAY_CTCP, normal_text); Parsing_Finished(); return; } if(slashme) { Classes.MsgDB->SetIrcChatMessage(screen, DISPLAY_MEACTION, help_buffer); } else { Classes.MsgDB->SetIrcChatMessage(screen, nickname, normal_text); } } Parsing_Finished(); return; } void Server::ParseCommand_NOTICE(void) { /* :nickname@addr NOTICE :message * :nickname@addr NOTICE :[#channel] channelmessage * :nickname@addr NOTICE #channel :message */ char notice_nickname[NICKNAME_LEN]; GetSenderName(notice_nickname, 0, NICKNAME_LEN); if(notice_nickname[0] == '\0') return; /* false format */ if(InputParameters[3][0] != ':') return; /* check if this is a channelnotice */ int channelmsg = 0; int len = (signed)strlen(InputParameters[3]); if(len >= 5 && !Check_Parameter_for_space(3)) { /* exapmle: ":[#A]" is possible, but ":[#]" or ":[# ]" is not ! */ if((InputParameters[3][0] == ':') && (InputParameters[3][1] == '[') && (InputParameters[3][2] == '#') && (InputParameters[3][len-1] == ']')) { /* ok, this is a notice for a channel */ Put_Text_together(4); channelmsg = 1; char notice_channel[CHANNELS_NAME_LEN]; int channelnamelen = len - 4; if(channelnamelen >= CHANNELS_NAME_LEN) channelnamelen = CHANNELS_NAME_LEN - 1; memcpy(notice_channel, &InputParameters[3][3], channelnamelen); notice_channel[channelnamelen] = '\0'; notice_channel[channelnamelen] = '\0'; snprintf(help_buffer, HELP_BUF_LEN, "%s: %s", notice_nickname, normal_text); int screen_nr = Classes.IrcScreen->GetScreenNumForChannel(notice_channel); Classes.MsgDB->SetIrcChatMessage(screen_nr, DISPLAY_NOTICE, help_buffer); Parsing_Finished(); } } if(!channelmsg) { Put_Text_together(3); int ctcp = 0; int len = strlen(normal_text); if((normal_text[0] == 1) && (normal_text[len-1] == 1)) { /* could be a CTCP reply */ ctcp = 1; if(len < 3) return; /* false format*/ int first_space_pos = position_of_num_char(normal_text, ' ', 1); normal_text[0] = normal_text[len-1] = '\0'; if(first_space_pos == 1) return; /* false format -> "\1 anything\1"*/ if(first_space_pos == len-2) return; /* false format -> "\1anything \1" */ if(first_space_pos != -1) { /* we have parameters */ normal_text[first_space_pos] = '\0'; string_toupper(normal_text+1); snprintf(help_buffer, HELP_BUF_LEN, "%s response from %s: \"%s\"", normal_text+1, notice_nickname, normal_text+first_space_pos+1); } else { snprintf(help_buffer, HELP_BUF_LEN, "%s response from %s without parameters", normal_text+1, notice_nickname); } Classes.MsgDB->SetIrcChatMessage(Classes.IrcScreen->GetActiveChannel(), DISPLAY_CTCP, help_buffer); } if(!ctcp) { int screen_nr = 0; if(InputParameters[2][0] == '#') { /* channelnotice from a user */ char tmp_channel[CHANNELS_NAME_LEN]; GetChannelName(tmp_channel, 2, CHANNELS_NAME_LEN); if(tmp_channel[0] == '\0') return; screen_nr = Classes.IrcScreen->GetScreenNumForChannel(tmp_channel); if(!screen_nr) return; } else { screen_nr = Classes.IrcScreen->GetActiveChannel(); } snprintf(help_buffer, HELP_BUF_LEN, "%s: %s", notice_nickname, normal_text); Classes.MsgDB->SetIrcChatMessage(screen_nr, DISPLAY_NOTICE, help_buffer); } } Parsing_Finished(); return; } void Server::ParseCommand_JOIN(void) { /* :user!~pcname@addr JOIN :#channel */ char tmp_channelname[CHANNELS_NAME_LEN]; char tmp_nickname[NICKNAME_LEN]; GetChannelName(tmp_channelname, 2, CHANNELS_NAME_LEN); GetSenderName(tmp_nickname, 0, NICKNAME_LEN); if(tmp_nickname[0] == '\0' || tmp_channelname[0] == '\0') return; /* false format */ if(strcmp(tmp_nickname, Classes.IrcUser->GetNickname()) == 0) { /* this is a join Message for our nickname */ int new_screen = Classes.IrcScreen->GetNotUsedScreen(0); /* get a screen for a channel */ if(!new_screen) return; Classes.IrcScreen->SetChannelName(new_screen, tmp_channelname); Classes.IrcScreen->SetActiveChannel(new_screen); snprintf(help_buffer, HELP_BUF_LEN, "You have joined #%s", tmp_channelname); Classes.MsgDB->SetIrcChatMessage(new_screen, DISPLAY_JOIN, help_buffer); Classes.IrcUserDB->Init_UserDB(tmp_channelname); /* create a new database for the usersnames in this channel */ Classes.IrcScreen->DrawBottomScreen(); Parsing_Finished(); return; } /* this is a normal join message * now check if there is a channel called like the string in tmp_channelname */ int screen = Classes.IrcScreen->GetScreenNr(tmp_channelname, 0); if(!screen) return; snprintf(help_buffer, HELP_BUF_LEN, "%s has joined #%s", tmp_nickname, tmp_channelname); Classes.MsgDB->SetIrcChatMessage(screen, DISPLAY_JOIN, help_buffer); Classes.IrcUserDB->Add_User(tmp_nickname, tmp_channelname); Classes.IrcScreen->DrawBottomScreen(); Parsing_Finished(); return; } void Server::ParseCommand_PART(void) { /* :user!~pcname@addr PART #channel :"message" */ char tmp_channelname[CHANNELS_NAME_LEN]; char tmp_nickname[NICKNAME_LEN]; GetChannelName(tmp_channelname, 2, CHANNELS_NAME_LEN); GetSenderName(tmp_nickname, 0, NICKNAME_LEN); if(tmp_nickname[0] == '\0' || tmp_channelname[0] == '\0') return; /* false format */ if(strcmp(tmp_nickname, Classes.IrcUser->GetNickname()) == 0) { /* this is a part Message for our nickname */ int screen = Classes.IrcScreen->GetScreenNr(tmp_channelname, 0); if(!screen) return; Classes.IrcScreen->EmptyScreen(screen); snprintf(help_buffer, HELP_BUF_LEN, "You have left #%s", tmp_channelname); Classes.MsgDB->SetIrcChatMessage(screen, DISPLAY_PART, help_buffer); Classes.IrcUserDB->Reset_UserDB(tmp_channelname); Classes.IrcScreen->DrawBottomScreen(); Parsing_Finished(); return; } /* this is a normal part message * now check if there is a channel called like the string in tmp_channelname */ int screen = Classes.IrcScreen->GetScreenNr(tmp_channelname, 0); if(!screen) return; /* now get the leave message */ Put_Text_together(3); if(normal_text[0] == '\0') { snprintf(help_buffer, HELP_BUF_LEN, "%s has left #%s", tmp_nickname, tmp_channelname); } else { snprintf(help_buffer, HELP_BUF_LEN, "%s has left #%s - %s", tmp_nickname, tmp_channelname, normal_text); } Classes.MsgDB->SetIrcChatMessage(screen, DISPLAY_PART, help_buffer); Classes.IrcUserDB->Remove_User_from_Channel(tmp_nickname, tmp_channelname); Classes.IrcScreen->DrawBottomScreen(); Parsing_Finished(); return; } void Server::ParseCommand_QUIT(void) { /* :nickname!pcname@addr QUIT :"leave-message" */ char tmp_nickname[NICKNAME_LEN]; GetSenderName(tmp_nickname, 0, NICKNAME_LEN); if(tmp_nickname == '\0') return; /* false format */ /* get the quit message */ Put_Text_together(2); if(normal_text[0] == '\0') { snprintf(help_buffer, HELP_BUF_LEN, "%s has quit from the IRC-Network", tmp_nickname); } else { snprintf(help_buffer, HELP_BUF_LEN, "%s has quit from the IRC-Network - %s", tmp_nickname, normal_text); } /* write a message to every channel this user was in */ for(int i = 1; i < CHANNELS_MAX; i++) { if(Classes.IrcScreen->GetScreenUse(i) == 0) continue; /* this screen is anyway not used */ if(Classes.IrcScreen->GetScreenType(i) == 1) { /* this screen is used for a direct chat */ if(strcmp(Classes.IrcScreen->GetDirectChatNick(i), tmp_nickname) == 0) { Classes.IrcScreen->EmptyScreen(i); Classes.MsgDB->SetIrcChatMessage(i, DISPLAY_QUIT, help_buffer); } } else { char * tmp_channel = Classes.IrcScreen->GetChannelName(i); if(tmp_channel == NULL) continue; int index = Classes.IrcUserDB->Is_User_in_Channel(tmp_nickname, tmp_channel); if(index != -1) { /* the user is in this channel */ Classes.IrcUserDB->Remove_User_from_Channel(index, tmp_channel); Classes.MsgDB->SetIrcChatMessage(i, DISPLAY_QUIT, help_buffer); } } } Classes.IrcScreen->DrawBottomScreen(); Parsing_Finished(); return; } void Server::ParseCommand_NICK(void) { /* :old_name!~pcname@ip NICK :new_name */ char tmp_nickname[NICKNAME_LEN]; GetSenderName(tmp_nickname, 0, NICKNAME_LEN); if(tmp_nickname[0] == '\0') return; /* false format */ if(InputParameters[2][0] != ':') return; make_first_char_away(InputParameters[2]); if(InputParameters[2][0] == '\0') return; if(strcmp(Classes.IrcUser->GetNickname(), tmp_nickname) == 0) { /* we changed our nickname */ Classes.IrcUser->SetNickname(InputParameters[2]); snprintf(help_buffer, HELP_BUF_LEN, "you have changed your nickname to %s", InputParameters[2]); if(Classes.IrcScreen->GetActiveChannel() == 0) /* we are on the server screen */ Classes.MsgDB->SetIrcChatMessage(0, DISPLAY_NICKNAME, help_buffer); Classes.IrcScreen->DrawBottomScreen(); } else { snprintf(help_buffer, HELP_BUF_LEN, "%s has changed his nickname to %s", tmp_nickname, InputParameters[2]); } int index; char * tmp_channel; int screen_nr = Classes.IrcScreen->GetScreenNumForDirectChat(tmp_nickname); if(screen_nr > 0) { Classes.IrcScreen->SetDirectChatNick(screen_nr, InputParameters[2]); Classes.IrcScreen->DrawTopScreen(); Classes.MsgDB->SetIrcChatMessage(screen_nr, DISPLAY_NICKNAME, help_buffer); } for(int i = 0; i < CHANNELS_MAX; i++) { /* check every screen if we have to update the informations */ if(Classes.IrcScreen->GetScreenUse(i) != 1) continue; /* this screen is not used */ if(Classes.IrcScreen->GetScreenType(i) == 0) { /* channel */ tmp_channel = Classes.IrcScreen->GetChannelName(i); index = Classes.IrcUserDB->Is_User_in_Channel(tmp_nickname, tmp_channel); if(index != -1) { /* replace the nickname for this user in the database and print a message on the screen */ Classes.IrcUserDB->Remove_User_from_Channel(index, tmp_channel); Classes.IrcUserDB->Add_User(InputParameters[2], tmp_channel); Classes.MsgDB->SetIrcChatMessage(i, DISPLAY_NICKNAME, help_buffer); } } else { /* direct chat */ } } Parsing_Finished(); return; } void Server::ParseCommand_MODE(void) { /* :who!pcname@network MODE #channel [:]+ [parameter2] [...] user modes : MODE [:]+ */ char tmp_channelname[CHANNELS_NAME_LEN]; char tmp_nickname[NICKNAME_LEN]; GetChannelName(tmp_channelname, 2, CHANNELS_NAME_LEN); GetSenderName(tmp_nickname, 0, NICKNAME_LEN); if(tmp_nickname[0] == '\0') return; /* false format*/ int screen_nr; int dblp = 1; int modelen = (signed)strlen(InputParameters[3]) - 1; if(InputParameters[3][0] != ':') dblp = 0; else modelen--; if(modelen < 1) return; /* false format -> not a single mode :/ */ if((InputParameters[3][dblp] != '-') && (InputParameters[3][dblp] != '+')) return; int plus = 1; if(InputParameters[3][dblp] == '-') plus = 0; if(tmp_channelname[0] == '\0') { screen_nr = Classes.IrcScreen->GetActiveChannel(); /* possibly user modes */ for(int i = 0; i < modelen; i++) { switch(InputParameters[3][i+1+dblp]) { case 'i': if(plus) { snprintf(help_buffer, HELP_BUF_LEN, "%s sets invisible mode on %s", tmp_nickname, InputParameters[2]); } else snprintf(help_buffer, HELP_BUF_LEN, "%s removes invisible mode from %s", tmp_nickname, InputParameters[2]); Classes.MsgDB->SetIrcChatMessage(screen_nr, DISPLAY_MODE, help_buffer); break; case 'w': if(plus) { snprintf(help_buffer, HELP_BUF_LEN, "%s sets the wallop flag on %s", tmp_nickname, InputParameters[2]); } else snprintf(help_buffer, HELP_BUF_LEN, "%s removes the wallop flag form %s", tmp_nickname, InputParameters[2]); Classes.MsgDB->SetIrcChatMessage(screen_nr, DISPLAY_MODE, help_buffer); break; case 'C': if(plus) { snprintf(help_buffer, HELP_BUF_LEN, "%s sets mode +C on %s (this user no longer receives CTCP messages)", tmp_nickname, InputParameters[2]); } else snprintf(help_buffer, HELP_BUF_LEN, "%s sets mode -C on %s (this user can receive CTCP messages)", tmp_nickname, InputParameters[2]); Classes.MsgDB->SetIrcChatMessage(screen_nr, DISPLAY_MODE, help_buffer); break; default: snprintf(help_buffer, HELP_BUF_LEN, "%s sets mode %c%c on %s", tmp_nickname, InputParameters[3][dblp], InputParameters[3][i+1+dblp], InputParameters[2]); Classes.MsgDB->SetIrcChatMessage(screen_nr, DISPLAY_MODE, help_buffer); break; } /* end of "switch(InputParameters[3][i+1+dblp])" */ } /* end of "for(int i = 0; i < modelen; i++)" */ } else { screen_nr = Classes.IrcScreen->GetScreenNumForChannel(tmp_channelname); /* channel modes */ int nextparameter = 0; for(int i = 0; i < modelen; i++) { switch(InputParameters[3][i+1+dblp]) { case 'l': if(plus) { snprintf(help_buffer, HELP_BUF_LEN, "%s set the user limit for this channel to %i", tmp_nickname, atoi(InputParameters[4+nextparameter])); nextparameter++; } else snprintf(help_buffer, HELP_BUF_LEN, "%s removes the user limit from this channel", tmp_nickname); Classes.MsgDB->SetIrcChatMessage(screen_nr, DISPLAY_MODE, help_buffer); break; case 'o': if(plus) { snprintf(help_buffer, HELP_BUF_LEN, "%s gives channel operator status to %s", tmp_nickname, InputParameters[4+nextparameter]); } else snprintf(help_buffer, HELP_BUF_LEN, "%s removes operator status from %s", tmp_nickname, InputParameters[4+nextparameter]); nextparameter++; Classes.MsgDB->SetIrcChatMessage(screen_nr, DISPLAY_MODE, help_buffer); break; case 'v': if(plus) { snprintf(help_buffer, HELP_BUF_LEN, "%s gives voice on %s", tmp_nickname, InputParameters[4+nextparameter]); } else snprintf(help_buffer, HELP_BUF_LEN, "%s removes voice on %s", tmp_nickname, InputParameters[4+nextparameter]); nextparameter++; Classes.MsgDB->SetIrcChatMessage(screen_nr, DISPLAY_MODE, help_buffer); break; case 'b': if(plus) { snprintf(help_buffer, HELP_BUF_LEN, "%s sets ban on %s", tmp_nickname, InputParameters[4+nextparameter]); } else snprintf(help_buffer, HELP_BUF_LEN, "%s removes ban on %s", tmp_nickname, InputParameters[4+nextparameter]); nextparameter++; Classes.MsgDB->SetIrcChatMessage(screen_nr, DISPLAY_MODE, help_buffer); break; case 'e': if(plus) { snprintf(help_buffer, HELP_BUF_LEN, "%s marks you as an identified user", tmp_nickname); } else snprintf(help_buffer, HELP_BUF_LEN, "%s marks you as no longer identified", tmp_nickname); Classes.MsgDB->SetIrcChatMessage(screen_nr, DISPLAY_MODE, help_buffer); break; case 'k': if(plus) { snprintf(help_buffer, HELP_BUF_LEN, "%s sets a password for this channel: \"%s\"", tmp_nickname, InputParameters[4+nextparameter]); } else snprintf(help_buffer, HELP_BUF_LEN, "%s removes the password from this channel, which was: \"%s\"", tmp_nickname, InputParameters[4+nextparameter]); nextparameter++; Classes.MsgDB->SetIrcChatMessage(screen_nr, DISPLAY_MODE, help_buffer); break; case 'n': if(plus) { snprintf(help_buffer, HELP_BUF_LEN, "%s set mode +n -> users outside this channel may not send messages to it", tmp_nickname); } else snprintf(help_buffer, HELP_BUF_LEN, "%s set mode -n -> users outside this channel may send messages to it", tmp_nickname); Classes.MsgDB->SetIrcChatMessage(screen_nr, DISPLAY_MODE, help_buffer); break; default: snprintf(help_buffer, HELP_BUF_LEN, "%s sets mode %c%c on %s", tmp_nickname, InputParameters[3][dblp], InputParameters[3][i+1+dblp], InputParameters[2]); Classes.MsgDB->SetIrcChatMessage(screen_nr, DISPLAY_MODE, help_buffer); break; } /* end of "switch(OneInputLine[position+1+i])" */ } /* end of "for(int i = 0; i < modelen; i++)"*/ } /* end of "if(tmp_channelname[0] == '\0')" */ Classes.IrcScreen->DrawBottomScreen(); Parsing_Finished(); return; } void Server::ParseCommand_KICK(void) { /* :admin_name!~pcname_of_admin@ip_of_admin KICK #channel kicked_person :reason */ char tmp_channelname[CHANNELS_NAME_LEN]; char tmp_nickname[NICKNAME_LEN]; GetChannelName(tmp_channelname, 2, CHANNELS_NAME_LEN); GetSenderName(tmp_nickname, 0, NICKNAME_LEN); if(tmp_channelname[0] == '\0' || tmp_nickname[0] == '\0') return; /* false format */ int tmp_channr = Classes.IrcScreen->GetScreenNr(tmp_channelname, 0); if(strcmp(Classes.IrcUser->GetNickname(), InputParameters[3]) == 0) { /* damn, we were kicked out :( */ if(Num_InputParameters >= 5) { /* we have a reason */ Put_Text_together(4); snprintf(help_buffer, HELP_BUF_LEN, "%s kicked you - reason: %s", tmp_nickname, normal_text); } else { snprintf(help_buffer, HELP_BUF_LEN, "%s kicked you", tmp_nickname); } Classes.IrcScreen->EmptyScreen(tmp_channr); Classes.IrcUserDB->Reset_UserDB(tmp_channelname); } else { if(Num_InputParameters >= 5) { /* we have a reason */ Put_Text_together(4); snprintf(help_buffer, HELP_BUF_LEN, "%s kicked %s - reason: %s", tmp_nickname, InputParameters[3], normal_text); } else { snprintf(help_buffer, HELP_BUF_LEN, "%s kicked %s", tmp_nickname, InputParameters[3]); } Classes.IrcUserDB->Remove_User_from_Channel(InputParameters[3], tmp_channelname); Classes.IrcScreen->DrawBottomScreen(); } Classes.MsgDB->SetIrcChatMessage(tmp_channr, DISPLAY_KICK, help_buffer); Parsing_Finished(); return; } void Server::ParseCommand_TOPIC(void) { TopicHandler(1); return; } void Server::ParseCommand_PING(void) { /* PING :number */ if(InputParameters[1][0] != ':' || strlen(InputParameters[1]) < 2) return; /* false format */ snprintf(help_buffer, HELP_BUF_LEN, "PONG %s", InputParameters[1]); WriteMessageToServer(help_buffer); Parsing_Finished(); return; } void Server::ParseCommand_WALLOPS(void) { /* :wallop!pcname@addr WALLOPS :wallop message */ char wallop[NICKNAME_LEN]; if(wallop[0] == '\0') return; /* hmmmm? */ GetSenderName(wallop, 0, NICKNAME_LEN); Put_Text_together(3); snprintf(help_buffer, HELP_BUF_LEN, "%s: %s", wallop, normal_text); Classes.MsgDB->SetIrcChatMessage(Classes.IrcScreen->GetActiveChannel(), DISPLAY_WALLOPS, help_buffer); Parsing_Finished(); return; } void Server::ParseCommand_SERVERNOTICE(void) { /* "NOTICE :*** " */ if(strcmp(InputParameters[2], ":***") == 0 && Num_InputParameters > 3) { Put_Text_together(3); Classes.MsgDB->SetIrcChatMessage(0, DISPLAY_AUTHINFO, normal_text); Parsing_Finished(); } return; } void Server::PingServer(void) { if(connect_status < STATUS_CONNECTED) return; /* do we have to send a ping? */ int time_now = time(NULL); if((time_now - last_ping) < DELAY_BETWEEN_PING) return; /* we have to send a ping */ last_ping = time_now; int random_lag_nr = (int)(1+(rand() % 1000000000)); snprintf(help_buffer, HELP_BUF_LEN, "PING LAG%i", random_lag_nr); WriteMessageToServer(help_buffer); return; } void Server::GetSenderName(char * Destination, int Source_Parameter, int max_dest_len) { Destination[0] = '\0'; if(Check_Parameter_for_space(Source_Parameter)) return; if(InputParameters[Source_Parameter][0] != ':') return; /* false format */ int position = position_of_num_char(InputParameters[Source_Parameter], '!', 1); if((position != -1) && (position < 2)) return; /* false format (we have a '!' but the format is ":!")*/ position--; /* 'position' is now the length of the nickname if we have a '!'. in the other case the rest of the string is the username */ if(position == -2) { int len = (signed)strlen(InputParameters[Source_Parameter]) - 1; if(len >= max_dest_len) len = max_dest_len - 1; memcpy(Destination, &InputParameters[Source_Parameter][1], len); Destination[len] = '\0'; } else { if(position >= max_dest_len) position = max_dest_len - 1; memcpy(Destination, &InputParameters[Source_Parameter][1], position); Destination[position] = '\0'; } return; } void Server::GetChannelName(char * Destination, int Source_Parameter, int max_dest_len) { Destination[0] = '\0'; if(Check_Parameter_for_space(Source_Parameter)) return; int msg_len = strlen(InputParameters[Source_Parameter]); int with_dblpoint = -1; if(InputParameters[Source_Parameter][0] == '#') { with_dblpoint = 0; } else if((InputParameters[Source_Parameter][0] == ':') || (InputParameters[Source_Parameter][1] == '#')) { with_dblpoint = 1; } else return; /* false format */ int channel_namelen = (msg_len - 1) - with_dblpoint; if(channel_namelen < 1) return; /* channel name is smaller than 1 char :) */ if(channel_namelen >= max_dest_len) channel_namelen = max_dest_len - 1; memcpy(Destination, &InputParameters[Source_Parameter][1+with_dblpoint], channel_namelen); Destination[channel_namelen] = '\0'; /* make the channel name to lowercase */ string_tolower(Destination); return; } void Server::PARTChannelorChat(char * user_input) { if(connect_status < STATUS_CONNECTED) return; int active_channel = Classes.IrcScreen->GetActiveChannel(); if(!active_channel) { Classes.MsgDB->SetIrcChatMessage(0, DISPLAY_PART, "cannot leave this screen :)"); return; } if(!Classes.IrcScreen->GetScreenUse(active_channel)) return; /* screen is not used */ if(Classes.IrcScreen->GetScreenType(active_channel) == 1) { /* this is a direct chat */ Classes.IrcScreen->EmptyScreen(active_channel); return; } /* we are in a channel */ int msg = 0; if(user_input) { if(strlen(user_input)) { /* we have a leavemsg */ snprintf(help_buffer, HELP_BUF_LEN, "PART #%s :%s", Classes.IrcScreen->GetChannelName(active_channel), user_input); msg = 1; } } if(!msg) { /* we havent got a leavemsg */ snprintf(help_buffer, HELP_BUF_LEN, "PART #%s :%s", Classes.IrcScreen->GetChannelName(active_channel), Classes.IrcUser->GetLeaveMessage()); } WriteMessageToServer(help_buffer); return; } void Server::QUITIrc(char * user_input) { if(connect_status < STATUS_CONNECTED) { Classes.IrcScreen->EndNcurses(); exit(0); } int msg = 0; if(user_input) { if(strlen(user_input)) { /* we have a leavemsg */ snprintf(help_buffer, HELP_BUF_LEN, "QUIT :%s", user_input); msg = 1; } } if(!msg) { /* we havent got a leavemsg */ snprintf(help_buffer, HELP_BUF_LEN, "QUIT :%s", Classes.IrcUser->GetLeaveMessage()); } WriteMessageToServer(help_buffer); Disconnect(); Classes.IrcScreen->EndNcurses(); exit(0); return; } void Server::JOINChannel(char * channel_name) { if(connect_status < STATUS_CONNECTED) return; int controll = 0; if(channel_name) { /* we have got a channel name */ controll = 1; int len = strlen(channel_name); if(len < 2) { controll = 0; } else { /* we have at least 2 chars */ if(channel_name[0] == '#') { snprintf(help_buffer, HELP_BUF_LEN, "JOIN %s", channel_name); WriteMessageToServer(help_buffer); } else controll = 0; } } if(!controll) { /* we do not have a channel name */ help_me("join"); } return; } void Server::DirectMSG(char * user_input) { if(connect_status < STATUS_CONNECTED) return; int controll = 0; if(user_input) { /* we have a nickname */ controll = 1; int len = strlen(user_input); int spacepos = position_of_num_char(user_input, ' ', 1); if((spacepos == -1) || (spacepos == 0)) { controll = 0; /* no space or space at the beginning */ } else if((len < 3) || (spacepos < 1) || (len-1 == spacepos)) { controll = 0; } else { user_input[spacepos] = '\0'; snprintf(help_buffer, HELP_BUF_LEN, "PRIVMSG %s :%s", user_input, user_input+spacepos+1); WriteMessageToServer(help_buffer); } } if(!controll) { /* no nickname given */ help_me("msg"); } return; } void Server::MECommand(char * user_input) { if(connect_status < STATUS_CONNECTED) return; int len; if(user_input) len = strlen(user_input); else len = 0; int active_channel = Classes.IrcScreen->GetActiveChannel(); if(len > 0) { if(!Classes.IrcScreen->GetScreenUse(active_channel) || !active_channel) { /* no chat or on the server screen */ Classes.MsgDB->SetIrcChatMessage(active_channel, DISPLAY_ERROR, "you cant use this command on this screen"); return; } snprintf(normal_text, HELP_BUF_LEN, "AACTION %s", user_input); int endpos = len+8; if(endpos >= HELP_BUF_LEN - 1) endpos = HELP_BUF_LEN - 2; normal_text[0] = normal_text[endpos] = 1; normal_text[endpos+1] = '\0'; snprintf(help_buffer, HELP_BUF_LEN, "%s %s", Classes.IrcUser->GetNickname(), user_input); Classes.MsgDB->SetIrcChatMessage(active_channel, DISPLAY_MEACTION, help_buffer); if(!Classes.IrcScreen->GetScreenType(active_channel)) { /* message for a channel */ snprintf(help_buffer, HELP_BUF_LEN, "PRIVMSG #%s :%s", Classes.IrcScreen->GetChannelName(active_channel), normal_text); } else { /* direct message */ snprintf(help_buffer, HELP_BUF_LEN, "PRIVMSG %s :%s", Classes.IrcScreen->GetDirectChatNick(active_channel), normal_text); } WriteMessageToServer(help_buffer); } else { help_me("me"); } return; } void Server::TopicHandler(int type) { /* type = 0: :network 332 #channel :topic * type = 1: :username!~pcname@ip_addr TOPIC #channel :new topic */ char tmp_channelname[CHANNELS_NAME_LEN]; if(type) { GetChannelName(tmp_channelname, 2, CHANNELS_NAME_LEN); } else { GetChannelName(tmp_channelname, 3, CHANNELS_NAME_LEN); } if(tmp_channelname[0] == '\0') return; /* false format */ int screen_nr = Classes.IrcScreen->GetScreenNr(tmp_channelname, 0); if(!screen_nr) return; /* no such channel */ if(type) { Put_Text_together(3); char tmp_nickname[NICKNAME_LEN]; GetSenderName(tmp_nickname, 0, NICKNAME_LEN); if(tmp_nickname[0] == '\0') return; /* false format */ snprintf(help_buffer, HELP_BUF_LEN, "%s set a new Topic: %s", tmp_nickname, normal_text); } else { Put_Text_together(4); snprintf(help_buffer, HELP_BUF_LEN, "Topic: %s", normal_text); } Classes.IrcScreen->SetTopic(screen_nr, normal_text); Classes.IrcScreen->DrawTopScreen(); Classes.MsgDB->SetIrcChatMessage(screen_nr, DISPLAY_TOPIC, help_buffer); Parsing_Finished(); return; } void Server::TOPIC_Change(char * user_input) { if(connect_status < STATUS_CONNECTED) return; int active_channel = Classes.IrcScreen->GetActiveChannel(); if((!Classes.IrcScreen->GetScreenUse(active_channel)) || (Classes.IrcScreen->GetScreenType(active_channel))) { /* screen is not used or direct chat */ Classes.MsgDB->SetIrcChatMessage(active_channel, DISPLAY_ERROR, "you are not in a channel, so you cant change the topic for this screen"); return; } if(user_input) { snprintf(help_buffer, HELP_BUF_LEN, "TOPIC #%s :%s", Classes.IrcScreen->GetChannelName(active_channel), user_input); } else { snprintf(help_buffer, HELP_BUF_LEN, "TOPIC #%s", Classes.IrcScreen->GetChannelName(active_channel)); } WriteMessageToServer(help_buffer); return; } void Server::NICK_Change(char * user_input) { if(!user_input) { help_me("nick"); return; } int pos = position_of_num_char(user_input, ' ', 1); if(pos == 0) { help_me("nick"); return; } if(pos != -1) user_input[pos] = '\0'; if(connect_status >= STATUS_CONNECTED) { /* we are connected */ snprintf(help_buffer, HELP_BUF_LEN, "NICK %s", user_input); WriteMessageToServer(help_buffer); } else { /* we are not connected */ Classes.IrcUser->SetNickname(user_input); int screen_nr = Classes.IrcScreen->GetActiveChannel(); snprintf(help_buffer, HELP_BUF_LEN, "changed your nickname to %s", user_input); Classes.MsgDB->SetIrcChatMessage(screen_nr, DISPLAY_NICKNAME, help_buffer); } return; } void Server::CTCP_User(char * user_input) { if(connect_status < STATUS_CONNECTED) return; if(user_input) { int space_pos = position_of_num_char(user_input, ' ', 1); if(space_pos == -1) { /* we have only 1 argument, so send a CTCP VERSION to this user */ snprintf(help_buffer, HELP_BUF_LEN, "PRIVMSG %s :", user_input); int len = strlen(help_buffer); if(len > HELP_BUF_LEN-10) return; /* we need enoug space to add "\1VERSION\1" */ strncat(help_buffer, "\1VERSION\1", 9); WriteMessageToServer(help_buffer); } else { /* we have to send a specific ctcp command */ if(user_input[space_pos+1] == '\0') return; /* we have a space, but there is no command after this */ string_toupper(user_input+space_pos+1); user_input[space_pos] = '\0'; snprintf(help_buffer, HELP_BUF_LEN, "PRIVMSG %s :\1%s\1", user_input, user_input+space_pos+1); WriteMessageToServer(help_buffer); } } else help_me("ctcp"); return; } void Server::Connect_to_Server(char * user_input) { if(user_input) { /* we dont really connect to this server, we only disconnect from the old server ond set the new parameters */ int len = strlen(user_input); int first_space_pos = position_of_num_char(user_input, ' ', 1); int second_space_pos = position_of_num_char(user_input, ' ', 2); if(first_space_pos == -1 && len) { /* we have a servername */ Classes.IrcUser->SetServername(user_input); Classes.IrcUser->SetPort(DEFAULT_PORT_NUM); do_connect = 1; Disconnect(); } else if(first_space_pos > 0 && len) { /* we have at least one space */ int portlen = 0; if(second_space_pos != -1) {/* we have more spaces -> wth ??? */ portlen = (second_space_pos - first_space_pos) - 1; user_input[second_space_pos] = '\0'; } else { portlen = (len - first_space_pos) - 1; } if(portlen < 1) return; user_input[first_space_pos] = '\0'; Classes.IrcUser->SetServername(user_input); Classes.IrcUser->SetPort(atoi(user_input+first_space_pos+1)); do_connect = 1; Disconnect(); } //else print help } else { /* we have no user input, this means we have to connect to the default server */ Disconnect(); Connect(); } return; } void Server::Parsing_Finished(void) { parsing_finished = 1; return; } void Server::DoStartupJobs(void) { if(connect_status < STATUS_ALL_OK) return; if(!ModesSet) { ModesSet = 1; char * modes = Classes.IrcUser->GetModes(); if(modes[0] != '\0') { snprintf(help_buffer, HELP_BUF_LEN, "MODE %s +%s", Classes.IrcUser->GetNickname(), modes); WriteMessageToServer(help_buffer); } } if(StartCommandsSent >= Classes.IrcUser->GetTotalCommandNum()) return; /* allready all commands sent */ int currenttime = time(NULL); if(LastCommandTime < currenttime) { /* only send one startup command every second */ LastCommandTime = currenttime; if((signed)strlen(Classes.IrcUser->GetStartupcommand(StartCommandsSent)) > 0) { Classes.IrcScreen->ParseCommandToServer(Classes.IrcUser->GetStartupcommand(StartCommandsSent)); } StartCommandsSent++; } return; } void Server::ResetParameters(void) { SetConnectStatus(STATUS_NOTHING); cs_printed = 0; StartCommandsSent = 0; ModesSet = 0; return; } int Server::GetNetworkSocket(void) { return socketfd; } void Server::PrintNormalText(char * nickname) { if(Num_InputParameters < 4) return; help_buffer[0] = '\0'; if(strcmp(InputParameters[2], Classes.IrcUser->GetNickname()) != 0) { /* nickname change by server */ Classes.IrcUser->SetNickname(InputParameters[2]); snprintf(help_buffer, HELP_BUF_LEN, "your nickname was changed by the server; new nickname: %s", InputParameters[2]); int screen_nr = Classes.IrcScreen->GetActiveChannel(); Classes.MsgDB->SetIrcChatMessage(screen_nr, DISPLAY_NICKNAME, help_buffer); if(screen_nr) Classes.MsgDB->SetIrcChatMessage(0, DISPLAY_NICKNAME, help_buffer); Classes.IrcScreen->DrawBottomScreen(); } Put_Text_together(3); Classes.MsgDB->SetIrcChatMessage(0, nickname, normal_text); Parsing_Finished(); return; } int Server::GetConnectStatus(void) { return connect_status; } void Server::SetConnectStatus(int new_status) { if(new_status < 0 || new_status > STATUS_MAX_NUM) return; connect_status = new_status; return; } int Server::GetMaybeReconnect(void) { return maybe_reconnect; } void Server::UnsetMaybeReconnect(void) { maybe_reconnect = 0; return; } int Server::GetDoConnect(void) { return do_connect; } #undef _SERVER_CC_