/* 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 "misc.h" #include "session.h" #include "file.h" #include "dccchat.h" #include "dccfile.h" #include "list.h" #include "magic.h" #include "fserv.h" #include "str_hash.h" #include "archdep.h" #include "appconf/appconf.h" #define MAGIC_SESSION 0x86dfc244 struct session { MAGIC magic; POOL pool; int id; /* The user structure is valid throughout the life of the session * since the session object registers interest in the user object. */ struct user *user; /* The chat is valid throughout the life of the session */ struct dccchat *chat; /* Current directory is valid throughout the CONNECTED life of * the session */ struct dir *current_dir; struct list *sends_list; /* List of struct dccfile's */ }; static int session_cb_open(struct eventmsg *msg); static int session_cb_close(struct eventmsg *msg); static int session_cb_msg(struct eventmsg *msg); static int session_cb_list_dir(struct dir *dir, const char *name, void *null); static int session_cb_list_file(struct dir *dir, const char *name, void *null); static int session_cmd_ls(struct eventmsg *msg); static int session_cmd_cd(struct eventmsg *msg); static int session_cmd_get(struct eventmsg *msg); static int session_cmd_unknown(struct eventmsg *msg); static int session_send_closed(struct eventmsg *msg); static int session_send_aborted(struct eventmsg *msg); static int session_send_finished(struct eventmsg *msg); static int session_event_filter(struct eventmsg *msg, void *filter); static int session_print_prompt(struct session *s); MODULE_NAME("session"); MODULE_INIT(session_init); MODULE_DESTROY(session_unload); MODULE_DEPENDS("server", "socket", "channel", "ctcp", "user", "appconf", "file"); MODULE_REGISTER(session); DEBUG session_debug; static POOL pool; static int session_global_id=0; struct eventobj *session_eventobj; struct list *session_list; int session_init() { session_debug = debug_register("session"); pool = pool_new(NULL); session_eventobj = event_create_obj(NULL,NULL); event_set_filter_func(session_eventobj,session_event_filter); session_list = list_create(pool); event_add_listener(session_eventobj,session_event_said, "ls", session_cmd_ls, NULL); event_add_listener(session_eventobj,session_event_said, "dir", session_cmd_ls, NULL); event_add_listener(session_eventobj,session_event_said, "cd", session_cmd_cd, NULL); event_add_listener(session_eventobj,session_event_said, "get", session_cmd_get, NULL); event_add_listener(session_eventobj,session_event_said_unknown, NULL, session_cmd_unknown, NULL); return 0; } int session_event_filter(struct eventmsg *msg, void *filter) { struct session_event_msg *sem; char *match = (char *) filter; char *said,*cp; int len=0; sem = msg->msg; ASSERT(is_magic(sem, MAGIC_SESSION_EVENT_MSG)); /* Only filter event_said messages */ if (msg->code != session_event_said || filter == NULL) return 0; said = sem->u.str; for (cp = said; *cp && !isspace(*cp); cp++) len++; if (strlen(match) != len) return -1; if (memcmp(match,said,len) == 0) return 0; /* Match */ return -1; } int session_unload() { return -1; } struct eventobj *session_get_eventobj() { return session_eventobj; } struct session *session_create(struct user *u, struct dir *root_dir) { struct session *s; POOL p; struct eventobj *chat_events; struct session_event_msg sem; p = pool_new(pool); s = XMALLOC(p, struct session); set_magic(s,MAGIC_SESSION); s->pool = p; s->id = session_global_id++; s->user = user_grab(u); s->sends_list = list_create(s->pool); s->current_dir = root_dir; s->chat = dccchat_start(u); chat_events = dccchat_get_event_obj(); event_add_listener(chat_events, dccchat_event_open, NULL,session_cb_open, s); event_add_listener(chat_events, dccchat_event_close, NULL,session_cb_close, s); event_add_listener(chat_events, dccchat_event_msg, NULL,session_cb_msg, s); set_magic(&sem,MAGIC_SESSION_EVENT_MSG); sem.session = s; sem.u.str = NULL; event_raise(session_eventobj, session_event_new, &sem); return s; } int session_cmd_unknown(struct eventmsg *msg) { struct session_event_msg *sem; const char *param; char *cmd; sem = msg->msg; ASSERT(is_magic(sem, MAGIC_SESSION_EVENT_MSG)); ASSERT(sem->session); ASSERT(sem->session->current_dir); param = strchr(sem->u.str,' '); cmd = tmp_strdupn(sem->u.str, ptrdiff(param,sem->u.str)/sizeof(char)); dccchat_write(sem->session->chat,"Unknown command: %s", cmd); session_print_prompt(sem->session); return 0; } int session_cmd_ls(struct eventmsg *msg) { struct session_event_msg *sem; struct dir *dir; sem = msg->msg; ASSERT(is_magic(sem, MAGIC_SESSION_EVENT_MSG)); ASSERT(sem->session); ASSERT(sem->session->current_dir); dir = sem->session->current_dir; dir->handler->set_app_data(dir,sem->session); dccchat_write(sem->session->chat,"Directory listing of folder %s", dir->handler->get_relative_name(dir)); dir->handler->list_dirs(dir, session_cb_list_dir,NULL); dir->handler->list_files(dir, session_cb_list_file,NULL); dccchat_write(sem->session->chat,"End of directory listing"); session_print_prompt(sem->session); return 0; } int session_cb_list_dir(struct dir *dir, const char *name, void *null) { struct session *s; s = (struct session *) dir->handler->get_app_data(dir); ASSERT(is_magic(s, MAGIC_SESSION)); dccchat_write(s->chat,"%-30s[DIR]",name); return 0; } int session_cb_list_file(struct dir *dir, const char *name, void *null) { struct session *s; struct file_handler *fh; struct file *file; size_t size; s = (struct session *) dir->handler->get_app_data(dir); ASSERT(is_magic(s, MAGIC_SESSION)); fh = find_file_handler(dir->handler->name); ASSERT(fh); file = fh->open(dir,name,file_flag_readonly); if (file == NULL) return 0; size = file->handler->get_size(file); file->handler->close(file); dccchat_write(s->chat,"%-30s%s",name,nice_size(size)); return 0; } int session_cmd_get(struct eventmsg *msg) { struct session_event_msg *sem; struct dir *cwd; struct file *file; struct file_handler *fh; struct dccfile *dccfile; const char *param; sem = msg->msg; ASSERT(is_magic(sem, MAGIC_SESSION_EVENT_MSG)); ASSERT(sem->session); ASSERT(sem->session->current_dir); param = strchr(sem->u.str,' '); while(isspace(*param)) param++; cwd = sem->session->current_dir; fh = find_file_handler(cwd->handler->name); ASSERT(fh); file = fh->open(cwd,param,file_flag_readonly); if (!file) { dccchat_write(sem->session->chat,"Can't find file %s in " "current directory", param); return 0; } dccchat_write(sem->session->chat,"About to send file"); dccfile = dccfile_start_send(sem->session->user,file); list_add_front(sem->session->sends_list, dccfile); event_add_listener(dccfile_get_event_obj(),dccfile_event_close, dccfile, session_send_closed, sem->session); event_add_listener(dccfile_get_event_obj(),dccfile_event_finished, dccfile, session_send_finished, sem->session); event_add_listener(dccfile_get_event_obj(),dccfile_event_aborted, dccfile, session_send_aborted, sem->session); return 0; } int session_cmd_cd(struct eventmsg *msg) { struct session_event_msg *sem; struct dir *cwd, *nwd; const char *param; sem = msg->msg; ASSERT(is_magic(sem, MAGIC_SESSION_EVENT_MSG)); ASSERT(sem->session); ASSERT(sem->session->current_dir); param = strchr(sem->u.str,' '); while(isspace(*param)) param++; cwd = sem->session->current_dir; nwd = cwd->handler->open(cwd,param); if (nwd != NULL) { cwd->handler->close(cwd); sem->session->current_dir = cwd = nwd; } else { dccchat_write(sem->session->chat,"Invalid directory"); } session_print_prompt(sem->session); return 0; } int session_send_closed(struct eventmsg *msg) { struct dccfile_event_msg *dem; struct session *s; dem = (struct dccfile_event_msg *)msg->msg; ASSERT(is_magic(dem, MAGIC_DCCFILE_EVENT_MSG)); s = (struct session *)msg->appdata; ASSERT(is_magic(s, MAGIC_SESSION)); dccchat_write(s->chat,"Send of file %s has closed", dem->file->handler->get_name(dem->file)); return 0; } int session_send_aborted(struct eventmsg *msg) { struct dccfile_event_msg *dem; struct session *s; dem = (struct dccfile_event_msg *)msg->msg; ASSERT(is_magic(dem, MAGIC_DCCFILE_EVENT_MSG)); s = (struct session *)msg->appdata; ASSERT(is_magic(s, MAGIC_SESSION)); dccchat_write(s->chat,"Send of file %s aborted", dem->file->handler->get_name(dem->file)); return 0; } int session_send_finished(struct eventmsg *msg) { struct dccfile_event_msg *dem; struct session *s; dem = (struct dccfile_event_msg *)msg->msg; ASSERT(is_magic(dem, MAGIC_DCCFILE_EVENT_MSG)); s = (struct session *)msg->appdata; ASSERT(is_magic(s, MAGIC_SESSION)); dccchat_write(s->chat,"Send of file %s finished", dem->file->handler->get_name(dem->file)); return 0; } int session_print_prompt(struct session *s) { dccchat_write(s->chat,"%s@%s:%s$", user_get_nick(s->user), user_get_hostname(s->user), s->current_dir->handler->get_relative_name(s->current_dir)); return 0; } int session_cb_open(struct eventmsg *msg) { struct session *s; struct dccchat *dc; struct dccchat_event_msg *dem; struct session_event_msg sem; dem = (struct dccchat_event_msg *)msg->msg; dc = dem->dccchat; ASSERT(is_magic(dc,MAGIC_DCCCHAT)); s = msg->appdata; ASSERT(is_magic(s,MAGIC_SESSION)); /* write debug msg */ notice(session_debug,"%d: %s!%s@%s on server %s has connected", s->id, user_get_nick(s->user), user_get_username(s->user), user_get_hostname(s->user), server_get_name(user_get_server(s->user))); /* send event msg */ set_magic(&sem,MAGIC_SESSION_EVENT_MSG); sem.session = s; sem.u.str = NULL; event_raise(session_eventobj, session_event_connected, &sem); /* Send MOTD, etc */ dccchat_write(s->chat,"Welcome to IRCfs (%s v%s) File Server", PACKAGE_NAME, PACKAGE_VERSION); /* Send prompt */ // dccchat_write(s->chat,"%s@%s:/$", // user_get_nick(s->user), // user_get_hostname(s->user)); session_print_prompt(s); return 0; } int session_cb_close(struct eventmsg *msg) { struct session *s; struct dccchat *dc; struct dccchat_event_msg *dem; struct session_event_msg sem; dem = (struct dccchat_event_msg *)msg->msg; dc = dem->dccchat; ASSERT(is_magic(dc,MAGIC_DCCCHAT)); s = msg->appdata; ASSERT(is_magic(s,MAGIC_SESSION)); /* write debug msg */ debug(session_debug,"%d: %s has disconnected", s->id, user_get_nick(s->user)); /* send event msg */ set_magic(&sem,MAGIC_SESSION_EVENT_MSG); sem.session = s; sem.u.str = NULL; event_raise(session_eventobj, session_event_disconnected, &sem); s->chat = NULL; session_destroy(s); return 0; } int session_cb_msg(struct eventmsg *msg) { struct session *s; struct dccchat *dc; struct dccchat_event_msg *dem; struct session_event_msg sem; dem = (struct dccchat_event_msg *)msg->msg; dc = dem->dccchat; ASSERT(is_magic(dc,MAGIC_DCCCHAT)); s = msg->appdata; ASSERT(is_magic(s,MAGIC_SESSION)); /* write debug msg */ info(session_debug,"%d: User said: %s", s->id, dem->msg); /* Find cmd handler */ /* send event msg */ set_magic(&sem,MAGIC_SESSION_EVENT_MSG); sem.session = s; sem.u.str = (char *)dem->msg; if (event_raise(session_eventobj, session_event_said, &sem) == 0) { /* No handlers found */ event_raise(session_eventobj, session_event_said_unknown, &sem); } return 0; } int session_reset_send_handler(struct list *l, struct dccfile *df, struct session *s) { event_del_listener(dccfile_get_event_obj(), dccfile_event_close, NULL, session_send_closed); event_del_listener(dccfile_get_event_obj(), dccfile_event_finished, NULL, session_send_finished); event_del_listener(dccfile_get_event_obj(), dccfile_event_aborted, NULL, session_send_aborted); return 0; } int session_destroy(struct session *s) { if (s->sends_list) { list_foreach(s->sends_list, (list_callback_t)session_reset_send_handler, s); list_destroy(s->sends_list); s->sends_list = NULL; } if (s->chat) { dccchat_destroy(s->chat); s->chat = NULL; } if (s->current_dir) { s->current_dir->handler->close(s->current_dir); s->current_dir = NULL; } if (s->user) user_release(s->user); pool_destroy(s->pool); return 0; } int session_write(struct session *s, const char *str) { ASSERT(is_magic(s, MAGIC_SESSION)); return dccchat_write_const(s->chat,str); } int session_writef(struct session *s, const char *str, ...) { va_list vl; int r; ASSERT(is_magic(s, MAGIC_SESSION)); va_start(vl,str); r = dccchat_write_v(s->chat,str,vl); va_end(vl); return r; } int session_vwritef(struct session *s, const char *str, va_list vl) { ASSERT(is_magic(s, MAGIC_SESSION)); return dccchat_write_v(s->chat,str,vl); } struct user *session_get_user(struct session *s) { ASSERT(is_magic(s, MAGIC_SESSION)); return s->user; } struct dir *session_get_current_dir(struct session *s) { ASSERT(is_magic(s, MAGIC_SESSION)); return s->current_dir; }