/* * Playground+ - intercom_glue.c * The intercom commands for the talker (by Grim) * --------------------------------------------------------------------------- */ #include "include/config.h" #ifdef INTERCOM #include <stdio.h> #include <unistd.h> #include <signal.h> #include <sys/socket.h> #include <sys/types.h> #include <sys/ioctl.h> #include <sys/un.h> #include <string.h> #include <stdarg.h> #include <sys/time.h> #ifndef BSDISH #include <malloc.h> #endif #include <stdlib.h> #include <ctype.h> #include "include/player.h" #include "include/intercom.h" #include "include/intercom_glue.h" #include "include/proto.h" extern void close_only_main_fd (void); #ifdef __GNUC__ void send_to_intercom (player *, const char *,...) __attribute__ ((format (printf, 2, 3))); #else void send_to_intercom (player *, const char *,...); #endif nameban *nameban_anchor = 0; extern struct command intercom_list[]; /*INTERNS */ nameban *check_intercom_banished_name (char *); player *make_dummy_intercom_player (void); static void tell_intercom_channel(char *); static void return_ppl_on_ichan(char *); void intercom_command (player * p, char *str) { if (!*str) { tell_player (p, " Format: intercom <sub command>\n"); return; } sub_command (p, str, intercom_list); return; } void view_intercom_commands (player * p, char *str) { view_sub_commands (p, intercom_list); } static void setup_namebans (void) { FILE *fp; char *oldstack; nameban *new_var; oldstack = stack; nameban_anchor = 0; fp = fopen ("files/interban", "r"); if (!fp) return; while (!feof (fp)) { *stack = 0; fgets (stack, MAX_NAME + 3, fp); if (*stack) { stack = strchr (oldstack, '\n'); if (stack) *stack = 0; new_var = (nameban *) MALLOC (sizeof (nameban)); memset (new_var, 0, sizeof (nameban)); oldstack[MAX_NAME - 1] = 0; strcpy (new_var->name, oldstack); new_var->type = 2; new_var->next = nameban_anchor; nameban_anchor = new_var; stack = oldstack; } } fclose (fp); return; } void start_intercom () { char intercom_name[MAX_TITLE + 10]; player *scan; sprintf (stack, "-=> %s <=- Intercom server on port %d", get_config_msg ("talker_name"), active_port - 1); stack[MAX_TITLE + 9] = 0; strcpy (intercom_name, stack); if (intercom_pid > 0 || intercom_fd > 0) kill_intercom (); if (establish_intercom_server () > 0) kill_intercom (); log ("intercom", "Forking to boot Intercom Server."); intercom_pid = fork (); switch (intercom_pid) { case 0: /*The child process */ /*Close all open sockets from this side */ close_only_main_fd (); for (scan = flatlist_start; scan; scan = scan->flat_next) if (scan->fd > 0) { close (scan->fd); } execlp ("bin/intercom", intercom_name, 0); log ("intercom", "Error, failed to exec intercom"); exit (1); break; case -1: log ("intercom", "Error, failed to fork main server"); break; } intercom_fd = -1; if (!nameban_anchor) setup_namebans (); intercom_last = time (NULL) + 2400; return; } void kill_intercom () { if (intercom_fd > 0) send_to_intercom (NULL, "%c", INTERCOM_DIE); intercom_fd = -1; if (!(sys_flags & SHUTDOWN) && (!current_player)) log ("error", "Shutting down intercom server.\n"); if (intercom_pid > 1) /*if (kill(intercom_pid, SIGHUP) < 0) */ kill (intercom_pid, SIGKILL); intercom_pid = -1; return; } int establish_intercom_server () { int this_fd; struct sockaddr_un sa; if (intercom_fd < -100) { /*FAiled to connect 100 times, thats for about 30 seconds. Kill the server and reboot it */ kill_intercom (); start_intercom (); } /*Connect to the intercom's unix socket */ this_fd = socket (PF_UNIX, SOCK_STREAM, 0); if (this_fd < 0) { log ("error", "Failed to create talker to intercoms unix socket"); return intercom_fd - 1; } sa.sun_family = AF_UNIX; strcpy (sa.sun_path, INTERCOM_SOCKET); if (connect (this_fd, (struct sockaddr *) &sa, sizeof (sa)) < 0) { if (intercom_fd == -2) log ("error", "Failed to connect to intercom unix socket"); close (this_fd); return intercom_fd - 1; } return this_fd; } void send_to_intercom (player * p, const char *fmt,...) { va_list varlist; char *oldstack; oldstack = stack; if (p && intercom_fd < 1) { tell_player (p, " The intercom is currently down.\n"); return; } va_start (varlist, fmt); vsprintf (stack, fmt, varlist); va_end (varlist); if (oldstack[strlen (oldstack) - 1] == (char) INCOMPLETE_MESSAGE || oldstack[strlen (oldstack) - 1] == (char) END_MESSAGE) stack = end_string (oldstack); else { stack = strchr (oldstack, 0); *stack++ = (char) END_MESSAGE; *stack++ = '\0'; } if (intercom_fd > 0) write (intercom_fd, oldstack, strlen (oldstack)); stack = oldstack; } static void send_intercom_portnumber (void) { send_to_intercom (NULL, "%c%d", PORTNUMBER_FOLLOWS, intercom_port); return; } static void intercom_su_wall (char *str) { char *oldstack; if (!str || !*str) return; oldstack = stack; sprintf (oldstack, "-=> %s", str); stack = end_string (oldstack); if (*(stack - 2) != '\n') { /*Late termination code for Nevyn */ sprintf ((stack - 1), "%s\n", COLOUR_TERMINATOR); stack = end_string (stack); } su_wall (oldstack); stack = oldstack; return; } static char *format_output (player * p, char *str) { char *ptr, *end_word, *oldstack = stack; int length = 0, longest = 0, line_pos; /*Firstly find the length of the longest element. NOTE we only format the first line returned to us */ ptr = str; if (!ptr) return str; while (*ptr && *ptr != '\n') { if (*ptr == ':') { if (length > longest) longest = length; length = 0; } else length++; ptr++; } if (length > longest) longest = length; /*To add padding, incriment the value of longest */ longest += 3; /*Now write everything to the stack */ line_pos = 0; ptr = str; while (*ptr && *ptr != '\n') { if (longest + line_pos + 2 > p->term_width) { *stack++ = '\n'; line_pos = 0; } end_word = ptr; /*Check if end_word is not : \0 or \n */ while (*end_word && !strchr ("\n:", *end_word)) end_word++; /*We need to have longest characters added, so add space padding */ length = longest - (end_word - ptr); while (length) { length--; *stack++ = ' '; } /*Copy the name in */ memcpy (stack, ptr, end_word - ptr); stack += (end_word - ptr); line_pos += longest; /*Now move the pointer on... */ if (*end_word == ':') ptr = end_word + 1; else ptr = end_word; } *stack = 0; strcat (oldstack, ptr); stack = end_string (stack); return oldstack; } static void intercom_tell_player (char *str, int format) { char *name, *msg; player *p; char *oldstack = stack, *stack_ptr, *end_ptr; name = str; if (!str || !*str) { log ("error", "Empty message in intercom_tell_player"); return; } msg = strchr (str, ':'); if (msg) *msg++ = '\0'; if (!msg || !*msg) return; p = find_player_global_quiet (name); if (!p) return; /*We have a player, p, so if we need to, format the output */ if (format) msg = format_output (p, msg); /*Put the whole thing on the stack, so we can add a \n on it. This is thanks to Nevyn at Crazylands, cos he threw away process output and now Crazylands cant handle the \n at the end cos of colour code methods. */ stack_ptr = stack; strcpy (stack_ptr, msg); stack = end_string (stack_ptr); end_ptr = stack - 1; if (end_ptr >= stack_ptr && *end_ptr != '\n') { sprintf (end_ptr, "%s\n", COLOUR_TERMINATOR); stack = end_string (end_ptr); } if (p->flags & PROMPT) pager (p, stack_ptr); else tell_player (p, stack_ptr); stack = oldstack; command_type = 0; return; } nameban *check_intercom_banished_name (char *str) { nameban *scan; scan = nameban_anchor; while (scan) { if (scan->name[0] && !strcasecmp (scan->name, str)) return scan; scan = scan->next; } return 0; } static void intercom_tell_player_and_return (char *str) { char *job_id, *name, *msg = 0, *ptr, *oldstack; player *p = 0; char end_was; char *end_pos; list_ent *l; saved_player *sp; char *end_ptr; if (!str || !*str) { log ("error", "Empty message in intercom_tell_player"); return; } job_id = str; name = strchr (job_id, ':'); if (name) { *name++ = '\0'; msg = strchr (name, ':'); if (msg) *msg++ = '\0'; } if (!msg || !*msg || !*name || !*job_id) return; if (strcasecmp (name, "me")) p = find_player_global_quiet (name); if (!p) { send_to_intercom (NULL, "%c%c%s:%s", REPLY_IS, NO_SUCH_PLAYER, job_id, name); command_type = 0; return; } if (p->tag_flags & BLOCK_TELLS) { send_to_intercom (NULL, "%c%c%s:%s", REPLY_IS, TALKER_BLOCKED, job_id, p->name); return; } /*Check the list entry isnt an ignore */ ptr = strchr (msg, '@'); if (!ptr) { log ("error", "intercom tried to send to player without a valid name."); return; } end_pos = ptr + 1; while (*end_pos && *end_pos != ',' && *end_pos != '\'' && *end_pos != ' ') end_pos++; end_was = *end_pos; *end_pos = '\0'; /*Now at the start of the message we have the name and address and thats it */ l = find_list_entry (p, msg); if (!l) l = find_list_entry (p, ptr); if (!l) l = find_list_entry (p, "@"); if (!l) { *ptr = '\0'; l = find_list_entry (p, msg); *ptr = '@'; } /*One quick check, is the sender a banished name here */ oldstack = stack; *ptr = '\0'; strcpy (oldstack, msg); *ptr = '@'; stack = end_string (oldstack); lower_case (oldstack); sp = find_saved_player (oldstack); if (sp) if (sp->residency == BANISHED || sp->residency & BANISHD) { send_to_intercom (NULL, "%c%c%s:%s", REPLY_IS, NAME_BANISHED, job_id, p->name); stack = oldstack; return; } if (check_intercom_banished_name (oldstack)) { send_to_intercom (NULL, "%c%c%s:%s", REPLY_IS, NAME_BANISHED, job_id, p->name); stack = oldstack; return; } stack = oldstack; *end_pos = end_was; if (l) { if (l->flags & IGNORE) { if (*(l->name) == '@') send_to_intercom (NULL, "%c%c%s:%s", REPLY_IS, TALKER_IGNORED, job_id, p->name); else send_to_intercom (NULL, "%c%c%s:%s", REPLY_IS, NAME_IGNORED, job_id, p->name); return; } if (l->flags & BLOCK) { if (*(l->name) == '@') send_to_intercom (NULL, "%c%c%s:%s", REPLY_IS, TALKER_BLOCKED, job_id, p->name); else send_to_intercom (NULL, "%c%c%s:%s", REPLY_IS, NAME_BLOCKED, job_id, p->name); return; } } /*Put the whole thing on the stack, so we can add a \n on it. This is thanks to Nevyn at Crazylands, cos he threw away process output and now Crazylands cant handle the \n at the end cos of colour code methods. */ strcpy (oldstack, msg); stack = end_string (oldstack); end_ptr = stack - 1; if (end_ptr >= oldstack && *end_ptr != '\n') { sprintf (end_ptr, "%s\n", COLOUR_TERMINATOR); stack = end_string (end_ptr); } if (p->flags & PROMPT) pager (p, oldstack); else tell_player (p, oldstack); send_to_intercom (NULL, "%c%c%s:%s", REPLY_IS, COMMAND_SUCCESSFUL, job_id, p->name); return; } player *make_dummy_intercom_player (void) { static player dummy; memset (&dummy, 0, sizeof (dummy)); current_player = &dummy; strcpy (dummy.name, "someone@intercom"); dummy.fd = intercom_fd; dummy.residency = NON_RESIDENT; dummy.term_width = 79; /* will cause probs for people with <79 widths */ dummy.misc_flags = NOCOLOR; /* PG+ specific */ return (&dummy); } static void parse_user_command_examine_in (char *str) { char *oldstack, *job_id, *name = 0; player *p; oldstack = stack; /*Format will be job_id:name */ job_id = str; if (job_id && *job_id) { name = strchr (job_id, ':'); if (name) *name++ = '\0'; } if (!name || !*name || !job_id || !*job_id) { log ("error", "Bad format in examine from intercom.\n"); return; } if (!strcasecmp (name, "me")) { send_to_intercom (NULL, "%c%c%s:me", REPLY_IS, NO_SUCH_PLAYER, job_id); return; } /*We know they are here, and exist, so we can examine, otherwise end */ send_to_intercom (NULL, "%c%c%s:x:%c", REPLY_IS, COMMAND_EXAMINE, job_id, (char) INCOMPLETE_MESSAGE); p = make_dummy_intercom_player (); newexamine (p, name); send_to_intercom (NULL, "%c", (char) END_MESSAGE); stack = oldstack; return; } static void parse_user_command_finger_in (char *str) { char *oldstack, *job_id, *name = 0; player *p; oldstack = stack; /*Format will be job_id:name */ job_id = str; if (job_id && *job_id) { name = strchr (job_id, ':'); if (name) *name++ = '\0'; } if (!name || !*name || !job_id || !*job_id) { log ("error", "Bad format in finger from intercom.\n"); return; } if (!strcasecmp (name, "me")) { send_to_intercom (NULL, "%c%c%s:me", REPLY_IS, NO_SUCH_PLAYER, job_id); return; } if (!strcasecmp (name, "friends")) { send_to_intercom (NULL, "%c%c%s:friends", REPLY_IS, NO_SUCH_PLAYER, job_id); return; } send_to_intercom (NULL, "%c%c%s:x:%c", REPLY_IS, COMMAND_FINGER, job_id, (char) INCOMPLETE_MESSAGE); p = make_dummy_intercom_player (); newfinger (p, name); send_to_intercom (NULL, "%c", (char) END_MESSAGE); stack = oldstack; return; } static void parse_user_command_who_in (char *str) { char *oldstack; player *scan; int count = 0; if (!str || !*str) return; oldstack = stack; scan = flatlist_start; while (scan) { if (scan->location) { sprintf (stack, "%s%s:", scan->location == intercom_room ? "*" : "", scan->name); stack = strchr (stack, 0); count++; } scan = scan->flat_next; } if (count > 0) { stack--; *stack = 0; } sprintf (stack, "\nThere %s currently %d user%s connected to ", count != 1 ? "are" : "is", count, count != 1 ? "s" : ""); stack = end_string (stack); send_to_intercom (NULL, "%c%c%s:x:%s", REPLY_IS, COMMAND_WHO, str, oldstack); stack = oldstack; return; } static void parse_user_command_lsu_in (char *str) { char *oldstack, *job_id; player *p; char empty_string[2]; empty_string[0] = 0; oldstack = stack; /*Format will be job_id */ job_id = str; if (!job_id || !*job_id) { log ("error", "Bad format in lsu from intercom.\n"); return; } send_to_intercom (NULL, "%c%c%s:x:%c", REPLY_IS, COMMAND_LSU, job_id, (char) INCOMPLETE_MESSAGE); p = make_dummy_intercom_player (); lsu (p, empty_string); send_to_intercom (NULL, "%c", (char) END_MESSAGE); stack = oldstack; return; } static void parse_user_command_locate_in (char *str) { char *job_id, *name = 0, *ptr; player *p; if (!str || !*str) return; job_id = str; if (job_id && *job_id) { name = strchr (job_id, ':'); if (name) { *name++ = 0; if (*name) { ptr = strchr (name, ':'); if (ptr) *ptr = 0; } } } if (!name || !*name || !job_id || !*job_id) { log ("error", "Bad format in parse_user_command_locate_in"); return; } p = find_player_absolute_quiet (name); if (p) send_to_intercom (NULL, "%c%c%s:%c", REPLY_IS, COMMAND_LOCATE, job_id, COMMAND_SUCCESSFUL); return; } static void parse_user_command_idle_in (char *str) { char *oldstack, *job_id, *name = 0; player *p; oldstack = stack; /*Format will be job_id:name */ job_id = str; if (job_id && *job_id) { name = strchr (job_id, ':'); if (name) *name++ = '\0'; } if (!name || !*name || !job_id || !*job_id) { log ("error", "Bad format in idle from intercom.\n"); return; } if (!strcasecmp (name, "me")) { send_to_intercom (NULL, "%c%c%s:me", REPLY_IS, NO_SUCH_PLAYER, job_id); return; } /*We know they are here, and exist, so we can examine, otherwise end */ send_to_intercom (NULL, "%c%c%s:x:%c", REPLY_IS, COMMAND_IDLE, job_id, (char) INCOMPLETE_MESSAGE); p = make_dummy_intercom_player (); check_idle (p, name); send_to_intercom (NULL, "%c", (char) END_MESSAGE); stack = oldstack; return; } static void parse_user_command_in (char *str) { if (!str || !*str) return; switch (*str) { case COMMAND_WHO: parse_user_command_who_in (str + 1); break; case COMMAND_EXAMINE: parse_user_command_examine_in (str + 1); break; case COMMAND_FINGER: parse_user_command_finger_in (str + 1); break; case COMMAND_LSU: parse_user_command_lsu_in (str + 1); break; case COMMAND_LOCATE: parse_user_command_locate_in (str + 1); break; case COMMAND_IDLE: parse_user_command_idle_in (str + 1); break; } return; } static void tell_intercom_room(char *str,int room_tag) { char *oldstack=stack,*ptr,*end_ptr,name[MAX_NAME],site[MAX_TALKER_ABBR+1]; player *scan; list_ent *l; ptr=str; end_ptr=strchr(ptr,':'); if (end_ptr) { *end_ptr++=0; if (strlen(ptr) > (MAX_NAME-1)) ptr[MAX_NAME-1]=0; strcpy(name,ptr); ptr=end_ptr; if (*ptr) { end_ptr=strchr(ptr,':'); if (end_ptr) { *end_ptr++=0; if (strlen(ptr) > (MAX_TALKER_ABBR-1)) ptr[MAX_TALKER_ABBR]=0; sprintf(site,"@%s",ptr); ptr=end_ptr; if (*ptr) strcpy(oldstack,ptr); } } } ptr=strchr(oldstack,0); /*Late termination code for Nevyn*/ if (*(ptr-1)!='\n') sprintf(ptr,"%s\n",COLOUR_TERMINATOR); stack=end_string(oldstack); if (room_tag) command_type|=ROOM; /*Do our own version of tell_room, cos we need to do intercom-based ignores*/ for (scan=intercom_room->players_top;scan;scan=scan->room_next) { sprintf(stack,"%s%s",name,site); l=find_list_entry(scan,stack); if (!l) l=find_list_entry(scan,site); if (!l) l=find_list_entry(scan,"@"); if (!l) l=find_list_entry(scan,name); if (!(l && l->flags & IGNORE)) tell_player(scan,oldstack); } if (room_tag) command_type&=~ROOM; stack=oldstack; return; } static void return_intercom_room_users (char *str) { player *scan; int count = 0; char *oldstack = stack; /*str will be the job ID */ scan = intercom_room->players_top; while (scan) { if (!(scan->room_next) && count > 0) { stack -= 2; strcpy (stack, " and "); stack += 5; } sprintf (stack, "%s, ", scan->name); stack = strchr (stack, 0); scan = scan->room_next; count++; } if (count == 0) /*There is nobody in the room, dont even reply */ return; /*There was someone here. We will have an extra ,_ at the end, so lets lose those */ stack -= 2; *stack++ = '.'; *stack++ = 0; send_to_intercom (NULL, "%c%s:%d:%s", INTERCOM_ROOM_LIST, str, count, oldstack); stack = oldstack; return; } static void do_room_move_inform(char *str) { char *oldstack=stack,name[MAX_NAME],*ptr,site[MAX_TALKER_ABBR]; strcpy(oldstack,str+1); ptr=strchr(oldstack,':'); if (ptr) { *ptr++=0; if (strlen(oldstack)>(MAX_NAME-1)) oldstack[MAX_NAME-1]=0; strcpy(name,oldstack); if (*ptr) { if (strlen(ptr)>(MAX_TALKER_ABBR-1)) ptr[MAX_TALKER_ABBR-1]=0; strcpy(site,ptr); } else strcpy(site,"somewhere"); } else { strcpy(name,"someone"); strcpy(site,"somewhere"); } switch(*str) { case ENTER_ROOM: sprintf(oldstack,"%s:%s@%s enters the intercom room.",str+1,name,site); break; case LEAVE_ROOM: sprintf(oldstack,"%s:%s@%s leaves the intercom room.",str+1,name,site); break; } stack=end_string(oldstack); tell_intercom_room(oldstack, 0); return; } static void parse_user_action(char *str) { switch(*str) { case ENTER_ROOM: case LEAVE_ROOM: do_room_move_inform(str); break; } return; } void parse_incoming_intercom () { char c; int chars_left; char *oldstack, *ptr; int make_formatted = 0; if (ioctl (intercom_fd, FIONREAD, &chars_left) == -1) { shutdown (intercom_fd, 2); close (intercom_fd); intercom_fd = -1; log ("error", "PANIC on FIONREAD on intercom_fd."); return; } if (!chars_left) { shutdown (intercom_fd, 2); close (intercom_fd); intercom_fd = -1; log ("error", "Link died on intercom_fd"); return; } oldstack = stack; c = (char) (END_MESSAGE - 1); while (chars_left && c != (char) END_MESSAGE) { chars_left--; if (read (intercom_fd, &c, 1) != 1) { log ("error", "Read error on intercom unix socket"); shutdown (intercom_fd, 2); close (intercom_fd); intercom_fd = -1; return; } if (c != (char) END_MESSAGE) *stack++ = c; } *stack++ = '\0'; intercom_last = time (NULL) + 1800; ptr = oldstack; command_type = 0; if (*ptr == HIGHLIGHT_RETURN) { command_type |= HIGHLIGHT; ptr++; } if (*ptr == PERSONAL_MESSAGE_TAG) { command_type |= PERSONAL; ptr++; } if (*ptr == FORMAT_MESSAGE_TAG) { make_formatted = 1; ptr++; } if (*ptr) { switch (*ptr) { case USER_COMMAND: parse_user_command_in (ptr + 1); break; case REQUEST_PORTNUMBER: send_intercom_portnumber (); break; case SU_MESSAGE: intercom_su_wall (ptr + 1); break; case PERSONAL_MESSAGE: intercom_tell_player (ptr + 1, make_formatted); break; case PERSONAL_MESSAGE_AND_RETURN: intercom_tell_player_and_return (ptr + 1); break; case PING: send_to_intercom (NULL, "%c", PING); break; case STARTING_CONNECT: break; case INTERCOM_ROOM_MESSAGE: tell_intercom_room(ptr+1,1); break; case INTERCOM_ROOM_LOOK: return_intercom_room_users (ptr + 1); break; case USER_ACTION: parse_user_action(ptr+1); break; case ICHAN_MESSAGE: tell_intercom_channel(ptr+1); break; case INTERCOM_ICHAN_WHO: return_ppl_on_ichan(ptr + 1); break; } } stack = oldstack; if (chars_left > 0) parse_incoming_intercom (); command_type = 0; return; } void add_intercom_server (player * p, char *str) { char *name, *abbr, *addr, *port, *oldstack; name = str; abbr = 0; addr = 0; port = 0; if (*name) { abbr = strchr (name, ':'); if (abbr) { *abbr++ = '\0'; if (*abbr) { addr = strchr (abbr, ':'); if (addr) { *addr++ = '\0'; if (*addr) { port = strchr (addr, ':'); if (port) *port++ = '\0'; } } } } } if (!port || !*port || !*addr || !*abbr || !name || !*name) { tell_player (p, "Format: add_server " "<name>:<abbreviation>:<address>:<port>\n"); return; } oldstack = stack; sprintf (oldstack, " Sending request to intercom to add %s to the database, " "at address %s %s, abbreviated to %s.\n", name, addr, port, abbr); stack = end_string (oldstack); tell_player (p, oldstack); stack = oldstack; send_to_intercom (p, "%c%s:%s:%s:%s:%s:O", ADD_NEW_LINK, p->name, name, abbr, addr, port); return; } void list_intercom_servers (player * p, char *str) { if (str && *str) { if (!strcasecmp (str, "hidden") && p->residency & PSU) { send_to_intercom (p, "%c%c%s:", SHOW_LINKS, LIST_HIDDEN, p->name); return; } if (!strcasecmp (str, "up")) { send_to_intercom (p, "%c%c%s:", SHOW_LINKS, LIST_UP, p->name); return; } if (isalpha (*str)) { send_to_intercom (p, "%c%c%s:", SHOW_LINKS, tolower (*str), p->name); } } send_to_intercom (p, "%c%c%s:", SHOW_LINKS, LIST_ALL, p->name); return; } void bar_talker (player * p, char *str) { if (!*str) { tell_player (p, " Format: bar <name>\n"); return; } send_to_intercom (p, "%c%s:%s", CLOSE_LINK, p->name, str); return; } void unbar_talker (player * p, char *str) { if (!*str) { tell_player (p, " Format: unbar <name>\n"); return; } send_to_intercom (p, "%c%s:%s", UNBAR_LINK, p->name, str); return; } void do_intercom_tell (player * p, char *str) { char *name, *talker, *msg, *oldstack; list_ent *l = 0; /*Assume we have a str and a space and a message, as we checked it before calling it */ name = str; msg = strchr (name, ' '); *msg++ = '\0'; if (strchr (name, ',')) { tell_player (p, " You cannot do chain tells to people and include remote" " talkers.\n"); return; } talker = strchr (name, '@'); if (talker) { l = find_list_entry (p, name); if (!l) l = find_list_entry (p, talker); *talker++ = '\0'; } if (!name || !*name || !talker || !*talker) { tell_player (p, " Badly formed remote address.\n"); return; } if (!l) l = find_list_entry (p, "@"); if (!l) l = find_list_entry (p, name); oldstack = stack; if (l) { if (l->flags & (IGNORE | BLOCK)) { sprintf (oldstack, " You cannot tell to them, as you are %sing" " %s.\n", l->flags & IGNORE ? "ignor" : "block", l->name); stack = end_string (oldstack); tell_player (p, oldstack); return; } } send_to_intercom (p, "%c%c%s:%s:%s:%s", USER_COMMAND, COMMAND_TELL, p->name, talker, name, msg); command_type = 0; return; } void do_intercom_remote (player * p, char *str) { char *name, *talker, *msg, *oldstack; list_ent *l = 0; /*Assume we have a str and a space and a message, as we checked it before calling it */ name = str; msg = strchr (name, ' '); *msg++ = '\0'; if (strchr (name, ',')) { tell_player (p, " You cannot do chain remotes to people and include remote" " talkers.\n"); return; } talker = strchr (name, '@'); if (talker) { l = find_list_entry (p, name); if (!l) l = find_list_entry (p, talker); *talker++ = '\0'; } if (!name || !*name || !talker || !*talker) { tell_player (p, " Badly formed remote address.\n"); return; } if (!l) l = find_list_entry (p, "@"); if (!l) l = find_list_entry (p, name); oldstack = stack; if (l) { if (l->flags & (IGNORE | BLOCK)) { sprintf (oldstack, " You cannot remote to them, as you are %sing" " %s.\n", l->flags & IGNORE ? "ignor" : "block", l->name); stack = end_string (oldstack); tell_player (p, oldstack); return; } } send_to_intercom (p, "%c%c%s:%s:%s:%s", USER_COMMAND, COMMAND_REMOTE, p->name, talker, name, msg); return; } void do_intercom_who (player * p, char *str) { /*Sanity check */ if (!*str || *str != '@' || !*(str + 1)) { log ("error", "Intercom who called with invalid arg"); return; } send_to_intercom (p, "%c%c%s:%s:%s:%s", USER_COMMAND, COMMAND_WHO, p->name, str + 1, "x", "x"); return; } void do_intercom_examine (player * p, char *str) { char *name, *location; name = str; location = 0; if (name && *name) { location = strchr (name, '@'); if (location) *location++ = '\0'; } if (!location || !*location || !name || !*name) { tell_player (p, " Format: examine user@location\n"); return; } send_to_intercom (p, "%c%c%s:%s:%s:%s", USER_COMMAND, COMMAND_EXAMINE, p->name, location, name, "x"); return; } void do_intercom_finger (player * p, char *str) { char *name, *location; name = str; location = 0; if (name && *name) { location = strchr (name, '@'); if (location) *location++ = '\0'; } if (!location || !*location || !name || !*name) { tell_player (p, " Format: finger user@location\n"); return; } send_to_intercom (p, "%c%c%s:%s:%s:%s", USER_COMMAND, COMMAND_FINGER, p->name, location, name, "x"); return; } void intercom_ping (player * p, char *str) { if (!*str) { tell_player (p, " Format: ping <talker>\n"); return; } send_to_intercom (p, "%c%s:%s", OPEN_LINK, p->name, str); return; } void close_intercom (player * p, char *str) { if (p->flags & BLOCK_SU) { tell_player (p, "Please go on duty to do that.\n"); return; } send_to_intercom (p, "%c%s:", CLOSE_ALL_LINKS, p->name); } void open_intercom (player * p, char *str) { if (p->flags & BLOCK_SU) { tell_player (p, "Please go on duty to do that.\n"); return; } send_to_intercom (p, "%c%s:", OPEN_ALL_LINKS, p->name); } void delete_intercom_server (player * p, char *str) { if (!*str) { tell_player (p, " Format: delete_server <name|alias>\n"); return; } send_to_intercom (p, "%c%s:%s", DELETE_LINK, p->name, str); return; } void intercom_change_name (player * p, char *str) { char *new_var; new_var = 0; if (*str) { new_var = strchr (str, ':'); if (new_var) *new_var++ = '\0'; } if (!new_var || !*new_var || !*str) { tell_player (p, " Format: change_name <old name>:<new name>\n"); return; } send_to_intercom (p, "%c%s:%s:%s", CHANGE_NAME, p->name, str, new_var); return; } void intercom_change_alias (player * p, char *str) { char *new_var; new_var = 0; if (*str) { new_var = strchr (str, ':'); if (new_var) *new_var++ = '\0'; } if (!new_var || !*new_var || !*str) { tell_player (p, " Format: change_alias <old alias>:<new alias>\n"); return; } send_to_intercom (p, "%c%s:%s:%s", CHANGE_ABBR, p->name, str, new_var); return; } void intercom_change_address (player * p, char *str) { char *new_var; new_var = 0; if (*str) { new_var = strchr (str, ':'); if (new_var) *new_var++ = '\0'; } if (!new_var || !*new_var || !*str) { tell_player (p, " Format: change_address <name|alias>:<new address>\n"); return; } send_to_intercom (p, "%c%s:%s:%s", CHANGE_ADDRESS, p->name, str, new_var); return; } void intercom_change_port (player * p, char *str) { char *new_var; new_var = 0; if (*str) { new_var = strchr (str, ':'); if (new_var) *new_var++ = '\0'; } if (!new_var || !*new_var || !*str) { tell_player (p, " Format: change_port <name|alias>:<new port>\n"); return; } send_to_intercom (p, "%c%s:%s:%s", CHANGE_PORT, p->name, str, new_var); return; } void intercom_reboot (player * p, char *str) { char *oldstack; oldstack = stack; tell_player (p, " Attempting to reboot intercom.\n"); sprintf (oldstack, "-=> %s reboots the intercom server.\n", p->name); stack = end_string (oldstack); su_wall_but (p, oldstack); stack = oldstack; kill_intercom (); start_intercom (); return; } void intercom_banish (player * p, char *str) { if (!*str) { tell_player (p, " Format: banish <name|alias>\n"); return; } if (p->flags & BLOCK_SU) { tell_player (p, "Please go on duty to do that.\n"); return; } send_to_intercom (p, "%c%s:%s", BANISH_SITE, p->name, str); return; } void intercom_update_servers (player * p, char *str) { if (!(*str)) { tell_player (p, " Requesting talker lists from all connected talkers.\n"); send_to_intercom (p, "%c", REQUEST_SERVER_LIST); } else { TELLPLAYER (p, " Requesting talker lists from %s.\n", str); send_to_intercom (p, "%c%c%s:%s:%s:%s", USER_COMMAND, COMMAND_UPDATE, p->name, str, "x", "x"); } return; } void intercom_request_stats (player * p, char *str) { send_to_intercom (p, "%c%s:%s", REQUEST_STATS, p->name, str); return; } void do_intercom_lsu (player * p, const char *str) { char empty_string[2]; empty_string[0] = 0; if (!(p->residency & PSU)) /*Only an SU can see SUs on another talker */ { lsu (p, empty_string); return; } /*Sanity check */ if (!*str || *str != '@' || !*(str + 1)) { lsu (p, empty_string); return; } send_to_intercom (p, "%c%c%s:%s:x:x", USER_COMMAND, COMMAND_LSU, p->name, str + 1); return; } void intercom_bar_name (player * p, char *str) { nameban *new_var; char *oldstack; if (!*str) { tell_player (p, " Format: intercom bar_name <name>.\n"); return; } if (p->flags & BLOCK_SU) { tell_player (p, "Please go on duty to do that.\n"); return; } if (strlen (str) > MAX_NAME - 1) str[MAX_NAME - 1] = 0; if (check_intercom_banished_name (str)) { tell_player (p, " That name is already barred.\n"); return; } new_var = (nameban *) MALLOC (sizeof (nameban)); memset (new_var, 0, sizeof (nameban)); if (nameban_anchor) new_var->next = nameban_anchor; nameban_anchor = new_var; strcpy (new_var->name, str); new_var->type = 1; oldstack = stack; sprintf (oldstack, " The name '%s' is now barred from the intercom.\n", str); stack = end_string (oldstack); tell_player (p, oldstack); sprintf (oldstack, "-=> %s bars the name '%s' from using the intercom.\n", p->name, str); stack = end_string (oldstack); su_wall (oldstack); stack = oldstack; return; } void intercom_unbar_name (player * p, char *str) { nameban *scan, *prev; char *oldstack; if (!*str) { tell_player (p, " Format: intercom unbar_name <name>.\n"); return; } if (p->flags & BLOCK_SU) { tell_player (p, "Please go on duty to do that.\n"); return; } scan = nameban_anchor; prev = 0; while (scan) { if (scan->name[0] && !strcasecmp (scan->name, str)) { if (scan->type == 2) { tell_player (p, " They are banished, you need to use intercom " "unbanish_name to re-permit them.\n"); return; } tell_player (p, " Name unbanished.\n"); oldstack = stack; sprintf (oldstack, "-=> %s allows the name '%s' to use the " "intercom.\n", p->name, str); stack = end_string (oldstack); su_wall (oldstack); stack = oldstack; if (prev) prev->next = scan->next; else nameban_anchor = scan->next; FREE (scan); return; } prev = scan; scan = scan->next; } tell_player (p, " No such name in the intercom barred lists.\n"); return; } void intercom_banish_name (player * p, char *str) { nameban *new_var; FILE *fp; char *oldstack; if (!*str) { tell_player (p, " Format: intercom banish_name <name>\n"); return; } if (p->flags & BLOCK_SU) { tell_player (p, "Please go on duty to do that.\n"); return; } new_var = check_intercom_banished_name (str); if (new_var) { if (new_var->type == 2) { tell_player (p, " That name is already banished.\n"); return; } tell_player (p, " Barred name, attempting to banish...\n"); } else { new_var = (nameban *) MALLOC (sizeof (nameban)); memset (new_var, 0, sizeof (nameban)); strcpy (new_var->name, str); new_var->type = 2; new_var->next = nameban_anchor; nameban_anchor = new_var; } /*Here we have new_var, and we need to just append it to the banished lists */ fp = fopen ("files/interban", "a"); if (!fp) { log ("error", "Error opening intercom banish file for writing.\n"); return; } fprintf (fp, "%s\n", str); fclose (fp); tell_player (p, " Name banished.\n"); oldstack = stack; sprintf (oldstack, "-=> %s banishes the name '%s' from using the intercom.\n", p->name, str); stack = end_string (oldstack); su_wall (oldstack); stack = oldstack; return; } static void sync_banish_names (void) { FILE *fp; nameban *scan; fp = fopen ("files/interban", "w"); if (!fp) { log ("error", " Error opening interban file for writing.\n"); return; } scan = nameban_anchor; while (scan) { if (scan->type == 2) fprintf (fp, "%s\n", scan->name); scan = scan->next; } fclose (fp); return; } void intercom_unbanish_name (player * p, char *str) { nameban *prev, *scan; char *oldstack; if (!*str) { tell_player (p, "Format: intercom unbanish_name <name>\n"); return; } if (p->flags & BLOCK_SU) { tell_player (p, "Please go on duty to do that.\n"); return; } scan = nameban_anchor; prev = 0; while (scan) { if (scan->name[0] && !strcasecmp (scan->name, str)) { if (scan->type == 1) tell_player (p, " Name unbarred.\n"); else tell_player (p, " Name unbanished.\n"); oldstack = stack; sprintf (oldstack, "-=> %s allows the name '%s' to use the " "intercom.\n", p->name, str); stack = end_string (oldstack); su_wall (oldstack); stack = oldstack; if (prev) prev->next = scan->next; else nameban_anchor = scan->next; if (scan->type == 2) sync_banish_names (); FREE (scan); return; } prev = scan; scan = scan->next; } tell_player (p, " That name is not in the banished list.\n"); return; } void intercom_slist (player * p, char *str) { send_to_intercom (p, "%c%s:", SHOW_ALL_LINKS_SHORT, p->name); return; } void intercom_hide (player * p, char *str) { if (!*str) { tell_player (p, " Format: intercom hide <talker>\n"); return; } send_to_intercom (p, "%c%s:%s", HIDE_ENTRY, p->name, str); return; } void intercom_unhide (player * p, char *str) { if (!*str) { tell_player (p, " Format: intercom unhide <talker>\n"); return; } send_to_intercom (p, "%c%s:%s", UNHIDE_ENTRY, p->name, str); return; } void intercom_version (player * p, char *str) { TELLPLAYER (p, " Intercom version %s (%s)\n", INTERCOM_VERSION, __DATE__); return; } void intercom_locate_name (player * p, char *str) { /*Sanity check */ if (!str || !*str) { tell_player (p, " Format: intercom locate <name>\n"); return; } send_to_intercom (p, "%c%c%s:x:%s:x", USER_COMMAND, COMMAND_LOCATE, p->name, str); return; } void do_intercom_idle (player * p, char *str) { char *name, *location = 0; name = str; if (name && *name) { location = strchr (name, '@'); if (location) *location++ = '\0'; } if (!location || !*location || !name || !*name || !(isalpha (*name))) { tell_player (p, " Format: idle user@location\n"); return; } send_to_intercom (p, "%c%c%s:%s:%s:%s", USER_COMMAND, COMMAND_IDLE, p->name, location, name, "x"); return; } void intercom_home (player * p, char *str) { /*If they are already there.... */ if (p->location == intercom_room) { tell_player (p, " You're already in the Intercom room!\n"); return; } /* or if they're stuck */ if (p->no_move) { tell_player (p, " You seem to be stuck to the ground.\n"); return; } /* otherwise move them */ move_to (p, "intercom.external", 0); } void do_intercom_say (player * p, char *str) { char *ptr, *oldstack; const char *method; oldstack = stack; ptr = strchr (str, 0); ptr--; if (ptr < str) { log ("error", "Zero length string passed to do_intercom_say\n"); return; } switch (*ptr) { case '!': method = "exclaim"; break; case '?': method = "ask"; break; default: method = "say"; break; } TELLPLAYER (p, " You %s '%s'\n", method, str); sprintf (oldstack, "%s %ss '%s'\n", p->name, method, str); stack = end_string (oldstack); tell_room_but (p, intercom_room, oldstack); stack = oldstack; send_to_intercom (p, "%c%c%s:x:x:%s", USER_COMMAND, COMMAND_SAY, p->name, str); return; } void do_intercom_emote (player * p, char *str) { char *oldstack; oldstack = stack; if (!str || !*str) { log ("error", "Zero length string passed to do_intercom_emote\n"); return; } if (*str == '\'') TELLPLAYER (p, " You emote: %s%s\n", p->name, str); else TELLPLAYER (p, " You emote: %s %s\n", p->name, str); if (*str == '\'') sprintf (oldstack, "%s%s\n", p->name, str); else sprintf (oldstack, "%s %s\n", p->name, str); stack = end_string (oldstack); tell_room_but (p, intercom_room, oldstack); stack = oldstack; send_to_intercom (p, "%c%c%s:x:x:%s", USER_COMMAND, COMMAND_EMOTE, p->name, str); return; } void intercom_room_look (player * p) { send_to_intercom (p, "%c%s:", INTERCOM_ROOM_LOOK, p->name); return; } void intercom_site_move (player * p, char *str) { char *site = 0, *port = 0; char *oldstack; oldstack = stack; site = str; if (p->flags & BLOCK_SU) { tell_player (p, "Please go on duty to do that.\n"); return; } if (site && *site) { port = strchr (site, ':'); if (port) *port++ = 0; } if (!port || !*port || !site || !*site) { tell_player (p, " Format: intercom announce_move sitename:portnumber\n"); return; } TELLPLAYER (p, " Informing all remote talkers of the address change to " "%s %s\n", site, port); send_to_intercom (p, "%c%s:%s", WE_ARE_MOVING, site, port); close_intercom (p, str); return; } void do_intercom_think (player * p, char *str) { char *oldstack; oldstack = stack; if (!str || !*str) { log ("error", "Zero length string passed to do_intercom_think\n"); return; } TELLPLAYER (p, " You think . o O ( %s )\n", str); sprintf (oldstack, "%s thinks . o O ( %s )\n", p->name, str); stack = end_string (oldstack); tell_room_but (p, intercom_room, oldstack); stack = oldstack; send_to_intercom (p, "%c%c%s:x:x:thinks . o O ( %s )", USER_COMMAND, COMMAND_EMOTE, p->name, str); return; } void intercom_dynamic (player * p, char *str) { FILE *fp; char *oldstack = stack; if (p->flags & BLOCK_SU) { tell_player (p, "Please go on duty to do that.\n"); return; } if (!str || !*str) { tell_player (p, " Format: intercom dynamic <sitename>\n"); return; } /*Save the file */ fp = fopen ("files/intercom.dynamic", "w"); if (!fp) { tell_player (p, "Couldnt open dynamic file.\n"); log ("error", "Failed to write to files/intercom.dynamic"); return; } fprintf (fp, "%s", str); fclose (fp); #ifdef VARARGS tell_player (p, " Locating as a dynamic server on %s\n", str); #else sprintf (oldstack, " Locating as a dynamic server on %s\n", str); stack = end_string (oldstack); tell_player (p, oldstack); stack = oldstack; #endif send_to_intercom (NULL, "%c", USE_DYNAMIC); return; } void do_intercom_room_enter_inform(player *p) { send_to_intercom(NULL,"%c%c%s",USER_ACTION,ENTER_ROOM,p->name); return; } void do_intercom_room_exit_inform(player *p) { send_to_intercom(NULL,"%c%c%s",USER_ACTION,LEAVE_ROOM,p->name); return; } #include "intercom_glue2.c" /* version stuff for pg_version */ void pg_intercom_version (void) { sprintf (stack, " -=*> Intercom server v%s (by Grim) enabled.\n", INTERCOM_VERSION); stack = strchr (stack, 0); } #endif