#ifndef __CHAT_H__ #define __CHAT_H__ /* Simple Chat Program * * (C) 2008 Bryce Schroeder */ #include #include #include #include #include #include #include #include #include #include #include #include #include /* for TCP_NODELAY in client */ #include #include /* -------------------------------- Administrator account ----------------- */ typedef struct ADMIN_T { char name[32]; char passwd[32]; char **allowed_cmnds; /* What commands is this administrator allowed to use? */ size_t allowed_count; int super; /* Allowed to use deadmin? We use this as the test for having power over other administrators. (Since with deadmin they could delete the other administrator's account, this is reasonable.) */ struct ADMIN_T *next; /* for linked list */ } admin_t; /* Create a new account from a line of the passwd file. */ admin_t *admin_new(FILE *line); admin_t *admin_new_dynamic(void); /* Is the administrator allowed to execute this command? */ int admin_allowed(admin_t *this, const char *cmd); /* Set the administrator's permission (allow is comma or space seperated) */ void admin_perm (admin_t *this, char *allow); /* Set the admin's password */ void admin_passwd (admin_t *this, const char *passwd); /* Is this admin a superadministrator? */ int admin_super (admin_t *this); /* write a line representing this account to the file. */ void admin_write (admin_t *this, FILE *file); /*-------------------------- General user struct------------------- */ typedef enum { DEAD = 0, LISTEN = 1, TALK = 2 } user_act_t; typedef struct USER_T { char name[32]; char hostname[32]; int ip_address; int port; /* what is the user doing? */ user_act_t activity; int scilenced; int hear_whispers; /* this is the socket descriptor */ int sockfd; /* this buffer holds the stuff we want to send to the user */ char buffer[65536]; size_t buffer_length; /* for flood control */ int flood_timer; admin_t *admin; /* Nonnull iff the user is an admin */ struct USER_T *next; /* linked list next pointer */ } user_t; /* constructor for new user connection */ user_t *user_new(int confd, const struct sockaddr *addr); void user_free(user_t *this); /* send some text to the user (non-blocking). works like printf. */ void user_send(user_t *this, const char *message, ...); void user_va_send(user_t *this, const char *message, va_list argptr); /* ----------------- The whole array of admin accounts ----------------- */ typedef struct { admin_t *user_list; } passwd_t; /* Load the password file from disk */ passwd_t *passwd_new(FILE *passwd); /* Write out the possibly modified password file */ void passwd_write(passwd_t *this, FILE *passwd); /* get a user account */ admin_t *passwd_get (passwd_t *this, const char *user); /* delete a user account */ void passwd_del (passwd_t *this, const char *user); /* create a admin new user */ void passwd_add (passwd_t *this, const char *user); /* login a user, adminifying them if login is good */ int passwd_login(passwd_t *this, user_t *user, const char *passwd); /* --------------------- The array of current users --------------- */ typedef struct { user_t *users; /* linked list */ /* It would be better to have this be a hash on the username * or a binary tree, but since the number of users is expected * to be low, I don't think it is worth the time in this simple * programming exercise. */ /* connected clients who may talk */ fd_set talk_set; /* clients who are listening */ fd_set listen_set; int flood_control; /* message of the day! */ char motd[2048]; int run_server; /* set to 0 to quit. */ passwd_t *passwd; char broadcast_buffer[65536]; int buffer_length; } users_t; /* make a new instance. */ users_t *users_new(passwd_t *passwd); /* connect a new user, maybe. if they are not accepted (e.g. name conflict) * they will be notified and bumped. */ void users_connect(users_t *this, int confd, const struct sockaddr *addr); /* this username taken? (by existing user) */ user_t *users_get(users_t *this, const char *name); /* remove the named user (e.g. after a disconnect.) */ void users_purge(users_t *this, const char *name); /* this is the heart of the program, network wise */ void users_do_network(users_t *this); /* broadcast to all users (non-blocking) */ void users_sendf(users_t *this, const char *message, ...); /* finished and time to quit? */ int users_run(users_t *this); /* ---------------- this object handles a command.------------------- */ typedef enum { UNREGULATED = 1, ADMIN = 2, SUPER = 4 } regulation_t; typedef struct COMMAND_T { const char *name; regulation_t regulated; /* is using this command limited? */ int (*function)(users_t *, user_t *, int argc, char *argv[]); const char *message; struct COMMAND_T *next; /* for linked list */ } command_t; /* attempt to execute a command. the message will be sent if * needed. returns 1 for success, 0 for failure. */ int command_exec(command_t *this, users_t *users, user_t *user, char *args); extern command_t commands[]; /* ------------ chat command list ------------------------- */ //int cmd_who (users_t *users, user_t *user); // not maintined ^ /* handles input from the users. */ void parse_input(users_t *users, user_t *user, char *buffer); /* is the user authorized? */ int authorized(const char *cmdname, regulation_t level, user_t *user); /* Helper functions 8--------------------------------------------*/ /* count the occurances of any of the chars in sep in str. */ size_t chrcnt(const char *str, const char *sep); /* copy string without whitespace */ void strcpystrip(char *dst, const char *src); #define MAX(x,y) ((x)>(y)?(x):(y)) #endif