aboutsummaryrefslogblamecommitdiffstats
path: root/mini_irc/mini_irc.c
blob: 326c9e887ae0e10e935393f85042b1d8e248c90b (plain) (tree)




















































































































































































































































































































































































                                                                                                                 
#include <ctype.h>
#include <errno.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include <netdb.h>
#include <sys/syscall.h>

static char *nick = "cbot_git";
static char *hostname = "irc.freenode.net";
static char *port = "6667";
static char *channel = "#mainlv";

static int conn;

#define IO_STR str_cat_buf

#define SYSC_WRITE(FD,X) write(FD,X,strlen(X));
#define SYSC_WRITE_O(FD,STR) write(FD,(STR).str,(STR).sz);write(0,"<< ",4);write(0,(STR).str,(STR).sz);
#define SYSC_WRITE_I(FD,STR) write(FD,(STR).str,(STR).sz);write(0,">> ",4);write(0,(STR).str,(STR).sz);
#define SYSC_WRITE_IO0(FD) write(FD,(IO_STR).str,(IO_STR).sz);write(0,"<< ",4);write(0,(IO_STR).str,(IO_STR).sz);

#define BUF_0(BUF)          (BUF).sz=0;
#define BUF_ADD_STR(BUF,X)  str_cat(BUF,X);
#define BUF_ADD_CHAR(BUF,C) {(BUF).str[(BUF).sz]=C;(BUF).sz+=1;}
#define BUF_CHAR(BUF,IDX)   (BUF).str[IDX]
#define BUF_SZ(BUF)         (BUF).sz
#define BUF_MAX(BUF)        ((BUF).sz==BUF_MAX_SZ)
#define BUF_SET0(BUF)       (BUF).str[(BUF).sz]=0;
#define BUF_STRCMP(BUF,STR) (!strncmp((BUF).str,STR,strlen(STR)))

#define STR_0() (IO_STR).sz=0;
#define STR_ADD(X) str_cat((&IO_STR),X);



#define BUF_MAX_SZ 1024
typedef struct pos_str
{
	int sz;
	char str[BUF_MAX_SZ+1];
} pos_str;

pos_str str_cat_buf;
pos_str str_buf;
pos_str serv_read;
pos_str serv_write;

#define TOK_CMP(IDX,STR) ((strlen(STR)==strlen(tok[IDX].s)) && !(strncmp(tok[IDX].s,STR,strlen(STR))))
#define TOK_NUM 20
typedef struct token
{
	char *s, *e;
} token;
static int tok_cnt=0;
token tok[TOK_NUM];

char* skip(char *s, char c) 
{
	while(*s != c && *s != '\0')
	{
		s++;
	}
	if(*s != '\0')
	{
		*s++ = '\0';
	}
	return s;
}

int str_cat(pos_str *buf, char *str)
{
	int i;
	int pos=0;
	int len = strlen(str);

	pos = buf->sz;
	for (i=0;(i<len)&&(pos+i<BUF_MAX_SZ);i++)
	{
		buf->str[pos+i] = str[i];
	}
	buf->sz = pos+i;

	return pos;
}

int print_str(int fd, char *str)
{
	int ret = 0;
	int len = strlen(str);

	write(fd, str, len);

	return ret;
}

/*
return fd!=ifconnection there
*/
int irc_connect( char *hostname, char *port )
{
	int fd=0;

	struct addrinfo serv, *res;

	memset(&serv, 0, sizeof(serv));
	serv.ai_family = AF_INET;
	serv.ai_socktype = SOCK_STREAM;
	getaddrinfo(hostname, port, &serv, &res);
	fd = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
	connect(fd, res->ai_addr, res->ai_addrlen);

	return fd;
}



int main()
{
	int i,j,m,len;
	int ret;
	char ch;
	int wordcount;
	char *user, *command, *where, *message, *iter, *start, *sep;
	print_str(0,"Start programm\n");
	
	//connect to server
	conn = irc_connect( hostname, port );
	if (conn<1)
	{
		SYSC_WRITE(1,"Cannot connect\n");
		return -1;
	}

	//send USER command
	STR_0();
	STR_ADD("USER ");
	STR_ADD(nick);
	STR_ADD(" 0 0 :");
	STR_ADD(nick);
	STR_ADD("\r\n");
	SYSC_WRITE_IO0(conn);

	//send NICK command
	STR_0();
	STR_ADD("NICK ");
	STR_ADD(nick);
	STR_ADD("\r\n");
	SYSC_WRITE_IO0(conn);

	BUF_0(str_buf);
	//server communication loop
	while (ret=read(conn, serv_read.str, BUF_MAX_SZ))
	{
		serv_read.sz = ret;
		serv_read.str[ret];
		//SYSC_WRITE_I(0,serv_read);

		//parse to get commands
		for (i=0;i<BUF_SZ(serv_read);i++)
		{
			BUF_ADD_CHAR(str_buf,BUF_CHAR(serv_read,i));
			ch = BUF_CHAR(serv_read,i);
			if ((i>0 
				&& (BUF_CHAR(serv_read,i) == '\n') 
				&& (BUF_CHAR(serv_read,i-1) == '\r')) 
				|| 
				(BUF_MAX(str_buf)))
			{
				BUF_SET0(str_buf);
				len = BUF_SZ(str_buf);
				//printf("len = %d\n",len);
				SYSC_WRITE_I(0,str_buf);
				
				//BUF_0(str_buf);
				//check if ping then answer to ping
				//if (BUF_STRCMP(str_buf,"PING"))
				//{
				//	STR_0();
				//	STR_ADD("PONG\r\n")
				//	SYSC_WRITE_IO0(conn);
				//} else 
				if (BUF_CHAR(str_buf,0) == ':')
				{
					#define START 1
					#define START_WORD 2
					#define CONTINUE 3
					#define MESSAGE 4
					#define END 5
					int state = START;
					//printf("TOKENIZING\n");
					//tokenize string
					tok_cnt = 0;
					iter = str_buf.str;

					for (j=0;j<len;j++)
					{

						
						switch(state)
						{
						case START:
							//printf("START %d %02x\n",j,iter[j]);
							if (iter[j]==' ')
							{
								break;
							}
							if (iter[j]=='\0')
							{
								state = END;
								break;
							}
							state = START_WORD;
							break;
						case START_WORD:
							//printf("WORD\n");
							tok[tok_cnt].s = iter+j;
							if (iter[j]==' ')
							{
								tok[tok_cnt].e = iter+j-1;
								tok_cnt += 1;
								state = START;
								break;
							}
							if (iter[j]=='\0')
							{
								tok[tok_cnt].e = iter+j-1;
								tok_cnt += 1;
								state = END;
								break;
							}
							if (iter[j]==':')
							{
								tok[tok_cnt].s = iter+j;
								//tok_cnt += 1;
								state = MESSAGE;
								break;
							}
							state = CONTINUE;
							break;
						case CONTINUE:
							//printf("CONTINUE\n");
							if ((iter[j]!=' ')&&(iter[j]!='\0'))
							{
								state = CONTINUE;
								break;
							}
							if (iter[j]=='\0')
							{
								tok[tok_cnt].e = iter+j-1;
								tok_cnt += 1;
								state = END;
								break;
							}
							if (iter[j]==' ')
							{
								tok[tok_cnt].e = iter+j-1;
								tok_cnt += 1;
								state = START_WORD;
								break;
							}
							//printf("Unknown state\n");
							break;
						case MESSAGE:
							//printf("MESSAGE\n");
							if ((iter[j]=='\0')||(iter[j]=='\n')||(iter[j]=='\r'))
							{
								tok[tok_cnt].e = iter+j-1;
								tok_cnt += 1;
								state = END;
								break;
							}
							state = MESSAGE;
							break;
						case END:
							//printf("END\n");
							break;
						default:
							printf("ERR STATE %d\n",state);
							return 0;
						};
						
					}
					if ((state==CONTINUE)||(state==MESSAGE))
					{
						tok[tok_cnt].e = iter+j-1;
						tok_cnt += 1;
					}
					for (j=0;j<tok_cnt;j++)
					{
						write(0,tok[j].s,tok[j].e-tok[j].s+1);
						*(tok[j].e+1)=0x0;
						write(0,"]\n",2);
					}
					if (tok_cnt < 2 ) continue;

					//replay on commands
					printf("CMD: %s\n",tok[1].s);
					if (TOK_CMP(1,"NOTICE?"))
					{
						STR_0();
						STR_ADD(tok[1].s);//command
						STR_ADD(" ");
						STR_ADD(tok[2].s)
						STR_ADD(" ");
						STR_ADD(tok[3].s);//message
						STR_ADD("\r\n");
						SYSC_WRITE_IO0(conn);
					} else if (TOK_CMP(1,"PING"))
					{
						STR_0();
						STR_ADD("PONG :");
						STR_ADD(tok[0].s);
						STR_ADD("\r\n");
						SYSC_WRITE_IO0(conn);
					} else if (TOK_CMP(1,"PRIVMSG"))
					{
						//join command
						if (TOK_CMP(3,":JOIN"))
						{
							STR_0();
							STR_ADD("JOIN ");
							STR_ADD(channel)
							STR_ADD("\r\n");
							SYSC_WRITE_IO0(conn);
						//echo
						} else
						{
							//if there is chan name then ech to chan
							if (tok[2].s[0]=='#')
							{
								STR_0();
								STR_ADD(tok[1].s);//command
								STR_ADD(" ");
								STR_ADD(tok[2].s);
								STR_ADD(" :");
								STR_ADD(tok[3].s+1);
								STR_ADD("\r\n");
								SYSC_WRITE_IO0(conn);
							} else
							{
								//get user name
								sep = strchr(tok[0].s,'!');
								tok[0].s[sep-tok[0].s] = 0x0;
								STR_0();
								STR_ADD(tok[1].s);//command
								STR_ADD(" ");
								STR_ADD(tok[0].s)
								STR_ADD(" :");
								//STR_ADD(tok[2].s);
								//STR_ADD("-");
								STR_ADD(tok[3].s+1);//message
								STR_ADD("\r\n");
								SYSC_WRITE_IO0(conn);
							}
						}
					}

				}

				BUF_0(str_buf);
			}
		}
	}
	

	print_str(0,"End program\n");

	return 0;
}