/*
* 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 <cstdio>
#include <cstring>
#include <ctime>
#include <cstdlib>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <fcntl.h>
#include <errno.h>
#include <pthread.h>
#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: <user> <mode> <unused> <realname>
*
* The USER command is used at the beginning of connection to specify
* the username, hostname and realname of a new user.
* The <mode> 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 <realname> 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 <nickname> +<modes> */
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 <your nickname> #channel +<channel modes> [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 <your nickname> #channel <unix-timestamp> */
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 <your nickname> #channel <the guy who set the topic> <unix-timestamp> */
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 <your nickname> (= or * or @) #channel :[@ or +]<nick1> [[[@ or +]<nick2>]] [[[@ or +]<nick n>]] */
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 <your nickname> :<message> */
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 <your nickname> :message
* :nickname@addr NOTICE <your nickname> :[#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 [:]+<modes> <parameter1> [parameter2] [...]
user modes :<nickname who changed a mode of a user> MODE <nickname of the target> [:]+<modes> */
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 <something> :*** <blabla text>" */
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 <your nickname> #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_
syntax highlighted by Code2HTML, v. 0.9.1