1
0
mirror of https://github.com/irssi/irssi.git synced 2024-12-04 14:46:39 -05:00
irssi/servertest/server.c

464 lines
13 KiB
C
Raw Normal View History

#include <common.h>
#include <irc-base/network.h>
#define FLOOD_TIMEOUT 100000
typedef struct
{
gchar *name;
GList *nicks;
}
CHANNEL_REC;
GList *channels;
gchar *clientnick, *clienthost;
int clienth;
/* Read a line */
gint read_line(gboolean socket, gint handle, GString *output, GString *buffer)
{
gchar tmpbuf[512];
gint recvlen, pos;
g_return_val_if_fail(handle != -1, -1);
g_return_val_if_fail(output != NULL, -1);
g_return_val_if_fail(buffer != NULL, -1);
g_string_truncate(output, 0);
recvlen = socket ?
net_receive(handle, tmpbuf, sizeof(tmpbuf)-1) :
read(handle, tmpbuf, sizeof(tmpbuf)-1);
if (recvlen <= 0)
{
if (buffer->len > 0)
{
/* no new data got but still something in buffer.. */
for (pos = 0; pos < buffer->len; pos++)
{
if (buffer->str[pos] == 13 || buffer->str[pos] == 10)
{
recvlen = 0;
break;
}
}
if (recvlen < 0 && buffer->len > 0)
{
/* connection closed and last line is missing \n ..
just add it so we can see if it had anything useful.. */
recvlen = 0;
g_string_append_c(buffer, '\n');
}
}
if (recvlen < 0) return -1;
}
else
{
/* append received data to buffer */
tmpbuf[recvlen] = '\0';
g_string_append(buffer, tmpbuf);
}
for (pos = 0; pos < buffer->len; pos++)
{
if (buffer->str[pos] == 13 || buffer->str[pos] == 10)
{
/* end of line */
buffer->str[pos] = '\0';
g_string_assign(output, buffer->str);
if (buffer->str[pos] == 13 && buffer->str[pos+1] == 10)
{
/* skip \n too */
pos++;
}
g_string_erase(buffer, 0, pos+1);
return 1;
}
}
/* EOL wasn't found, wait for more data.. */
return 0;
}
void client_send(char *text)
{
write(clienth, text, strlen(text));
write(clienth, "\r\n", 2);
}
void makerand(char *str, int len)
{
for (; len > 0; len--)
*str++ = (rand() % 20)+'A';
}
void makerand2(char *str, int len)
{
#if 0
gchar c;
while (len > 0)
{
c = rand() & 255;
if (c != 0 && c != 13 && c != 10)
{
*str++ = c;
len--;
}
}
#else
makerand(str, len);
#endif
}
void send_cmd(void)
{
static gint nicks = 0;
GList *tmp;
char str[512];
int pos;
/* send msg to every channel */
str[511] = '\0';
for (tmp = g_list_first(channels); tmp != NULL; tmp = tmp->next)
{
CHANNEL_REC *rec = tmp->data;
makerand(str, 511);
str[0] = ':';
str[10] = '!';
str[20] = '@';
switch (rand() % 10)
{
case 0:
/* join */
pos = 2+sprintf(str+2, "%d", nicks++); /* don't use same nick twice */
str[pos] = '-';
str[10] = '\0';
g_list_append(rec->nicks, g_strdup(str+1));
str[10] = '!';
sprintf(str+30, " JOIN :%s", rec->name);
break;
case 1:
/* part */
if (g_list_length(rec->nicks) > 1 && rand() % 3 == 0)
{
gchar *nick;
nick = g_list_nth(rec->nicks, rand()%(g_list_length(rec->nicks)-1)+1)->data;
if (rand() % 3 == 0)
sprintf(str, ":kicker!some@where KICK %s %s :go away", rec->name, nick);
else if (rand() % 3 == 0)
sprintf(str, ":%s!dunno@where QUIT %s :i'm outta here", nick, rec->name);
else
sprintf(str, ":%s!dunno@where PART %s", nick, rec->name);
rec->nicks = g_list_remove(rec->nicks, nick);
g_free(nick);
}
else
str[0] = '\0';
break;
case 2:
/* nick change */
if (g_list_length(rec->nicks) > 1)
{
gchar *nick;
nick = g_list_nth(rec->nicks, rand()%(g_list_length(rec->nicks)-1)+1)->data;
pos = sprintf(str, ":%s!dunno@where NICK ", nick);
str[pos] = '_';
str[50] = '\0';
rec->nicks = g_list_remove(rec->nicks, nick);
rec->nicks = g_list_append(rec->nicks, g_strdup(str+pos));
g_free(nick);
}
else
str[0] = '\0';
break;
case 3:
/* topic */
pos = 30+sprintf(str+30, " TOPIC %s :", rec->name);
str[pos] = 'x';
break;
case 4:
/* mode */
sprintf(str+30, " MODE %s :%cnt", rec->name, (rand() & 1) ? '+' : '-');
break;
case 5:
/* notice */
pos = 30+sprintf(str+30, " NOTICE %s :", rec->name);
str[pos] = 'X';
break;
case 6:
/* nick mode change */
if (g_list_length(rec->nicks) > 1)
{
gchar *nick;
nick = g_list_nth(rec->nicks, rand()%(g_list_length(rec->nicks)-1)+1)->data;
pos = sprintf(str, ":server MODE %s +%c %s", rec->name, rand()&1 ? 'o' : 'v', nick);
str[pos] = '_';
str[50] = '\0';
rec->nicks = g_list_remove(rec->nicks, nick);
rec->nicks = g_list_append(rec->nicks, g_strdup(str+pos));
g_free(nick);
}
else
str[0] = '\0';
break;
default:
pos = 30+sprintf(str+30, " PRIVMSG %s :", rec->name);
makerand2(str+pos, 511-pos);
if (rand() % 4 == 0)
{
pos += sprintf(str+pos, "\001ACTION ");
str[510] = 1;
}
else if (rand() % 10 == 0)
{
pos += sprintf(str+pos, "\001VERSION\001");
pos++;
}
else if (rand() % 2 == 0)
{
pos += sprintf(str+pos, "%s: ", clientnick);
}
str[pos] = 'X';
break;
}
client_send(str);
}
makerand(str, 511);
str[0] = ':';
str[10] = '!';
str[20] = '@';
switch (rand() % 11)
{
case 0:
/* join */
if (g_list_length(channels) < 20)
{
CHANNEL_REC *rec;
int n, pos;
n = (rand()%20)+25;
pos = sprintf(str, ":%s!%s JOIN :", clientnick, clienthost);
str[pos] = '#';
str[n] = '\0';
rec = g_new(CHANNEL_REC, 1);
rec->name = g_strdup(str+pos);
rec->nicks = g_list_append(NULL, g_strdup(clientnick));
channels = g_list_append(channels, rec);
client_send(str);
sprintf(str, ":server 353 %s = %s :@%s", clientnick, rec->name, clientnick);
client_send(str);
sprintf(str, ":server 366 %s %s :End of /NAMES list.", clientnick, rec->name);
}
else
str[0] = '\0';
break;
case 1:
/* leave channel (by kick) */
if (g_list_length(channels) > 3)
{
CHANNEL_REC *chan;
chan = g_list_nth(channels, rand()%g_list_length(channels))->data;
if (rand() % 3 != 0)
{
pos = sprintf(str, ":%s!%s PART %s :", clientnick, clienthost, chan->name);
str[pos] = 'x';
}
else
{
str[0] = ':';
sprintf(str+30, " KICK %s %s :byebye", chan->name, clientnick);
}
g_free(chan->name);
g_list_foreach(chan->nicks, (GFunc) g_free, NULL); g_list_free(chan->nicks);
g_free(chan);
channels = g_list_remove(channels, chan);
}
else
str[0] = '\0';
break;
case 2:
/* ctcp version */
sprintf(str+30, " PRIVMSG %s :\001VERSION\001", clientnick);
break;
case 3:
/* ctcp ping */
sprintf(str+30, " PRIVMSG %s :\001PING\001", clientnick);
break;
case 4:
/* user mode */
sprintf(str+30, " MODE %s :%ciw", clientnick, (rand() & 1) ? '+' : '-');
break;
case 5:
/* msg */
pos = 30+sprintf(str+30, " PRIVMSG %s :", clientnick);
str[pos] = 'X';
break;
case 6:
/* notice */
pos = 30+sprintf(str+30, " NOTICE %s :", clientnick);
str[pos] = 'X';
break;
case 7:
/* invite */
pos = 30+sprintf(str+30, " INVITE %s", clientnick);
str[pos] = 'X';
break;
case 8:
/* error */
pos = sprintf(str, ":server ERROR :");
str[pos] = 'X';
break;
case 9:
/* wallops */
pos = sprintf(str, ":server WALLOPS :");
str[pos] = 'X';
break;
case 10:
/* ping */
pos = sprintf(str, ":server PING :");
str[pos] = 'X';
break;
}
client_send(str);
}
void handle_command(char *str)
{
if (strncmp(str, "NICK ", 5) == 0)
{
clientnick = g_strdup(str+5); /* got the nick */
}
}
guint gui_timeout_add(guint32 interval, GUITimeoutFunction function, gpointer data)
{
return -1;
}
int main(void)
{
static fd_set fdset;
struct timeval tv;
int serverh, port;
IPADDR ip;
#ifdef HAVE_IPV6
if (net_gethostname("::1", &ip) != 0)
{
printf("net_gethostname()\n");
return 1;
}
#else
if (net_gethostname("127.0.0.1", &ip) != 0)
{
printf("net_gethostname()\n");
return 1;
}
#endif
srand(0);
port = 6660;
serverh = net_listen(&ip, &port);
if (serverh == -1)
{
printf("listen()\n");
return 1;
}
clienth = -1; channels = NULL;
for (;;)
{
FD_ZERO(&fdset);
if (clienth != -1) FD_SET(clienth, &fdset);
FD_SET(serverh, &fdset);
tv.tv_sec = 0;
tv.tv_usec = FLOOD_TIMEOUT;
if (select((serverh > clienth ? serverh : clienth)+1, &fdset, NULL, NULL, &tv) <= 0)
{
/* nothing happened, bug the client with some commands.. */
if (clienth != -1 && clientnick != NULL) send_cmd();
}
else
{
if (FD_ISSET(serverh, &fdset))
{
/* client connecting! */
if (clienth != -1)
{
/* only one client allowed.. */
int handle;
handle = net_accept(serverh, NULL, &port);
if (handle != -1)
{
client_send("Only one client allowed");
close(handle);
continue;
}
}
else
{
IPADDR clientip;
clienth = net_accept(serverh, &clientip, &port);
if (clienth != -1)
{
clienthost = g_strdup(net_ip2host(&clientip));
client_send(":server 001 pla");
client_send(":server 002 plapla");
client_send(":server 003 plaplapla");
client_send(":server 004 connected!");
}
}
}
else
{
/* clients sending something.. */
GString *str, *buf;
int ret;
str = g_string_new(NULL);
buf = g_string_new(NULL);
do
{
ret = read_line(TRUE, clienth, str, buf);
if (ret == -1)
{
/* client disconnected */
close(clienth);
clienth = -1;
break;
}
if (ret == 1) handle_command(str->str);
}
while (ret == 1);
g_string_free(str, TRUE);
g_string_free(buf, TRUE);
}
}
}
return 0;
}