/* IRCfs - IRC FileServ for *nix. * Copyright (C) 2002 Nick 'Zaf' Clifford * For licensing details, refer to the LICENSE file in the source * code directory. */ #include "runtime.h" #include "module.h" #include "dccchat.h" #include "user.h" #include "magic.h" #include "event.h" #include "list.h" #include "server.h" #include "socket.h" #include "timer.h" #include "appconf/appconf.h" #include #include struct dccchat { MAGIC magic; POOL pool; struct server *server; struct user *user; char *nick; //Copy of users nickname. (they may leave IRC) struct socket *socket; struct timer *connect_timer; }; static int dccchat_server_goes(struct eventmsg *msg); static int dccchat_user_goes(struct eventmsg *msg); static int dccchat_raise_event(struct dccchat *dc, enum dccchat_events e, const char *str); static int dccchat_new_connect(struct socket *socket, enum socket_event_type e, void *d); static int dccchat_request_timeout(struct timer *t, void *appdata); MODULE_NAME("dccchat"); MODULE_INIT(dccchat_init); MODULE_DESTROY(dccchat_unload); MODULE_DEPENDS("user","select","socket","server"); MODULE_REGISTER(dccchat); struct eventobj *dccchat_eventobj; DEBUG dccchat_debug; POOL dccchat_pool; static struct list *sessions; struct eventobj *user_eventobj; int dccchat_init() { dccchat_debug = debug_register("dccchat"); dccchat_pool = pool_new(NULL); dccchat_eventobj = event_create_obj(NULL,NULL); //event_set_filter_func(user_eventobj,user_event_filter); sessions = list_create(dccchat_pool); return 0; } int dccchat_unload() { return -1; } struct dccchat *dccchat_start(struct user *u) { static char tmpbuf[125]; struct dccchat *dc; unsigned long ip; struct in_addr ina; int timeout; POOL p; p = pool_new(dccchat_pool); dc = XMALLOC(p,struct dccchat); set_magic(dc,MAGIC_DCCCHAT); dc->pool = p; dc->server = user_get_server(u); dc->user = user_grab(u); dc->nick = pstrdup(p,user_get_nick(u)); dc->socket = socket_create(socket_type_tcp); if (dc->socket == NULL) { pool_destroy(p); return NULL; } event_add_listener(server_get_event_obj(), server_event_disconnected, dc->server, dccchat_server_goes, dc); event_add_listener(user_get_event_obj(), user_event_quit, dc->user, dccchat_user_goes, dc); list_add_end(sessions, dc); /* TODO setup socket */ socket_bind(dc->socket); socket_set_callback(dc->socket,socket_event_connect, dccchat_new_connect,dc); socket_listen(dc->socket); socket_get_local_addr(dc->socket, tmpbuf, sizeof(tmpbuf)); debug(dccchat_debug,"Setup listening socket on %s:%d", tmpbuf,socket_get_local_port(dc->socket)); ip = server_get_my_addr_long(dc->server); if (ip == 0) { debug(dccchat_debug,"Can't do DCC CHAT. Don't know my own " "IP address"); pool_destroy(p); return NULL; } ina.s_addr = ip; debug(dccchat_debug,"My Address: %lu %s", ip, inet_ntoa(ina)); ip = htonl(ip); server_send(dc->server,"PRIVMSG %s :%cDCC CHAT chat %lu %u%c", dc->nick,0x01,ip, socket_get_local_port(dc->socket),0x01); timeout = 120; conf_value_to_int(conf_get_value(dc->pool, "/dcc/chat/request_timeout"),&timeout); dc->connect_timer = timer_start(timeout,dccchat_request_timeout, dc); return dc; } void dccchat_destroy(struct dccchat *dc) { ASSERT(is_magic(dc,MAGIC_DCCCHAT)); debug(dccchat_debug,"DCCChat(%s) destroying", dc->nick); if (dc->user) user_release(dc->user); /* Disable callbacks */ socket_set_callback(dc->socket,socket_event_close, NULL,NULL); socket_destroy(dc->socket); dccchat_raise_event(dc, dccchat_event_close, ""); if (list_find_data(sessions,dc)) list_del_current(sessions); if (dc->connect_timer) timer_destroy(dc->connect_timer); clear_magic(dc); pool_destroy(dc->pool); return; } int dccchat_request_timeout(struct timer *t, void *appdata) { struct dccchat *dc; dc = appdata; ASSERT(is_magic(dc, MAGIC_DCCCHAT)); warn(dccchat_debug,"request timeout!"); dccchat_destroy(dc); return 0; } struct eventobj *dccchat_get_event_obj() { return dccchat_eventobj; } int dccchat_user_goes(struct eventmsg *msg) { struct dccchat *dc; struct user_event_msg *uem; dc = msg->appdata; uem = msg->msg; ASSERT(is_magic(dc,MAGIC_DCCCHAT)); ASSERT(is_magic(uem, MAGIC_USER_EVENT_MSG)); ASSERT(dc->user == uem->user); debug(dccchat_debug,"DCCChat(%s) user has left IRC", dc->nick); /* We don't need to do anything, since we have grabbed the user */ return 0; } int dccchat_server_goes(struct eventmsg *msg) { struct dccchat *dc; struct server *s; dc = msg->appdata; s = msg->msg; ASSERT(is_magic(dc,MAGIC_DCCCHAT)); ASSERT(dc->server == s); debug(dccchat_debug,"DCCChat(%s) server disconnected", dc->nick); dc->server = NULL; return 0; } int dccchat_socket_read(struct socket *socket, enum socket_event_type e, void *d) { struct dccchat *dc; static char linebuf[512]; char *cp; int r; dc = (struct dccchat *) d; ASSERT(is_magic(dc,MAGIC_DCCCHAT)); ASSERT(dc->socket == socket); while(1) { r = socket_readline(dc->socket,linebuf,512); if (r == -1) { dccchat_destroy(dc); return 0; } if (r == 0) { break; } cp = strchr(linebuf,'\r'); if (cp) *cp = 0; cp = strchr(linebuf,'\n'); if (cp) *cp = 0; debug(dccchat_debug,"Read: %s",linebuf); dccchat_raise_event(dc, dccchat_event_msg, linebuf); } return 0; } int dccchat_socket_closed(struct socket *socket, enum socket_event_type e, void *d) { struct dccchat *dc; dc = (struct dccchat *) d; ASSERT(is_magic(dc,MAGIC_DCCCHAT)); ASSERT(dc->socket == socket); dccchat_destroy(dc); return 0; } int dccchat_new_connect(struct socket *socket, enum socket_event_type e, void *d) { struct dccchat *dc; struct socket *newsock; dc = (struct dccchat *) d; ASSERT(is_magic(dc,MAGIC_DCCCHAT)); ASSERT(dc->socket == socket); newsock = socket_accept(socket); socket_destroy(dc->socket); dc->socket = newsock; socket_set_callback(dc->socket,socket_event_read, dccchat_socket_read,dc); socket_set_callback(dc->socket,socket_event_close, dccchat_socket_closed,dc); socket_set_buffer_size(dc->socket,1024); debug(dccchat_debug,"DCCChat(%s) user connected", dc->nick); dccchat_raise_event(dc, dccchat_event_open, dc->nick); if (dc->connect_timer) { timer_destroy(dc->connect_timer); dc->connect_timer = NULL; } return 0; } int dccchat_raise_event(struct dccchat *dc, enum dccchat_events e, const char *str) { struct dccchat_event_msg msg; set_magic(&msg,MAGIC_DCCCHAT_EVENT_MSG); msg.who = dc->user; msg.msg = str; msg.dccchat = dc; return event_raise(dccchat_eventobj,e,&msg); } int dccchat_write(struct dccchat *dc, const char *format, ...) { va_list va; int r; ASSERT(is_magic(dc,MAGIC_DCCCHAT)); va_start(va, format); r = dccchat_write_v(dc, format, va); va_end(va); return r; } int dccchat_write_v(struct dccchat *dc, const char *format, va_list va) { int r; ASSERT(is_magic(dc,MAGIC_DCCCHAT)); r = socket_vprintf(dc->socket,format,va); if (r == -1) return r; if (socket_write(dc->socket,"\r\n",2) == -1) return -1; return r; } int dccchat_write_const(struct dccchat *dc, const char *str) { ASSERT(is_magic(dc,MAGIC_DCCCHAT)); socket_write(dc->socket,str,strlen(str)); if (socket_write(dc->socket,"\r\n",2) == -1) return -1; return 0; }