/* $Header: /cvsroot/fbmuck/fbmuck/src/help.c,v 1.11 2003/06/23 00:13:48 revar Exp $ */ #include "config.h" /* commands for giving help */ #include "db.h" #include "props.h" #include "params.h" #include "tune.h" #include "interface.h" #include "externs.h" #include <sys/types.h> #include <sys/stat.h> #include <ctype.h> /* * Ok, directory stuff IS a bit ugly. */ #if defined(HAVE_DIRENT_H) || defined(_POSIX_VERSION) # include <dirent.h> # define NLENGTH(dirent) (strlen((dirent)->d_name)) #else /* not (HAVE_DIRENT_H or _POSIX_VERSION) */ # define dirent direct # define NLENGTH(dirent) ((dirent)->d_namlen) # ifdef HAVE_SYS_NDIR_H # include <sys/ndir.h> # endif /* HAVE_SYS_NDIR_H */ # ifdef HAVE_SYS_DIR_H # include <sys/dir.h> # endif /* HAVE_SYS_DIR_H */ # ifdef HAVE_NDIR_H # include <ndir.h> # endif /* HAVE_NDIR_H */ #endif /* not (HAVE_DIRENT_H or _POSIX_VERSION) */ #if defined(HAVE_DIRENT_H) || defined(_POSIX_VERSION) || defined(HAVE_SYS_NDIR_H) || defined(HAVE_SYS_DIR_H) || defined(HAVE_NDIR_H) # define DIR_AVALIBLE #endif #if defined(STANDALONE_HELP) # define dbref int int notify(dbref player, const char *msg) { return printf("%s\n", msg); } int string_prefix(register const char *string, register const char *prefix) { while (*string && *prefix && tolower(*string) == tolower(*prefix)) string++, prefix++; return *prefix == '\0'; } int string_compare(register const char *s1, register const char *s2) { while (*s1 && tolower(*s1) == tolower(*s2)) s1++, s2++; return (tolower(*s1) - tolower(*s2)); } char* strcpyn(char* buf, size_t bufsize, const char* src) { int pos = 0; char* dest = buf; while (++pos < bufsize && *src) { *dest++ = *src++; } *dest = '\0'; return buf; } char* strcatn(char* buf, size_t bufsize, const char* src) { int pos = strlen(buf); char* dest = &buf[pos]; while (++pos < bufsize && *src) { *dest++ = *src++; } if (pos <= bufsize) { *dest = '\0'; } return buf; } #endif void spit_file_segment(dbref player, const char *filename, const char *seg) { FILE *f; char buf[BUFFER_LEN]; char segbuf[BUFFER_LEN]; char *p; int startline, endline, currline; startline = endline = currline = 0; if (seg && *seg) { strcpy(segbuf, seg); for (p = segbuf; isdigit(*p); p++) ; if (*p) { *p++ = '\0'; startline = atoi(segbuf); while (*p && !isdigit(*p)) p++; if (*p) endline = atoi(p); } else { endline = startline = atoi(segbuf); } } if ((f = fopen(filename, "r")) == NULL) { snprintf(buf, sizeof(buf), "Sorry, %s is missing. Management has been notified.", filename); notify(player, buf); fputs("spit_file:", stderr); perror(filename); } else { while (fgets(buf, sizeof buf, f)) { for (p = buf; *p; p++) { if (*p == '\n' || *p == '\r') { *p = '\0'; break; } } currline++; if ((!startline || (currline >= startline)) && (!endline || (currline <= endline))) { if (*buf) { notify(player, buf); } else { notify(player, " "); } } } fclose(f); } } void spit_file(dbref player, const char *filename) { spit_file_segment(player, filename, ""); } void index_file(dbref player, const char *onwhat, const char *file) { FILE *f; char buf[BUFFER_LEN]; char topic[BUFFER_LEN]; char *p; int arglen, found; *topic = '\0'; strcpy(topic, onwhat); if (*onwhat) { strcatn(topic, sizeof(topic), "|"); } if ((f = fopen(file, "r")) == NULL) { snprintf(buf, sizeof(buf), "Sorry, %s is missing. Management has been notified.", file); notify(player, buf); fprintf(stderr, "help: No file %s!\n", file); } else { if (*topic) { arglen = strlen(topic); do { do { if (!(fgets(buf, sizeof buf, f))) { snprintf(buf, sizeof(buf), "Sorry, no help available on topic \"%s\"", onwhat); notify(player, buf); fclose(f); return; } } while (*buf != '~'); do { if (!(fgets(buf, sizeof buf, f))) { snprintf(buf, sizeof(buf), "Sorry, no help available on topic \"%s\"", onwhat); notify(player, buf); fclose(f); return; } } while (*buf == '~'); p = buf; found = 0; buf[strlen(buf) - 1] = '|'; while (*p && !found) { if (strncasecmp(p, topic, arglen)) { while (*p && (*p != '|')) p++; if (*p) p++; } else { found = 1; } } } while (!found); } while (fgets(buf, sizeof buf, f)) { if (*buf == '~') break; for (p = buf; *p; p++) { if (*p == '\n' || *p == '\r') { *p = '\0'; break; } } if (*buf) { notify(player, buf); } else { notify(player, " "); } } fclose(f); } } #if !defined(STANDALONE_HELP) void mcppkg_help_request(McpFrame * mfr, McpMesg * msg, McpVer ver, void *context) { FILE *f; const char* file; char buf[BUFFER_LEN]; char topic[BUFFER_LEN]; char *p; int arglen, found; McpVer supp = mcp_frame_package_supported(mfr, "org-fuzzball-help"); McpMesg omsg; if (supp.verminor == 0 && supp.vermajor == 0) { notify(mcpframe_to_user(mfr), "MCP: org-fuzzball-help not supported."); return; } if (!string_compare(msg->mesgname, "request")) { char *onwhat; char *valtype; onwhat = mcp_mesg_arg_getline(msg, "topic", 0); valtype = mcp_mesg_arg_getline(msg, "type", 0); *topic = '\0'; strcpy(topic, onwhat); if (*onwhat) { strcatn(topic, sizeof(topic), "|"); } if (!string_compare(valtype, "man")) { file = MAN_FILE; } else if (!string_compare(valtype, "mpi")) { file = MPI_FILE; } else if (!string_compare(valtype, "help")) { file = HELP_FILE; } else if (!string_compare(valtype, "news")) { file = NEWS_FILE; } else { snprintf(buf, sizeof(buf), "Sorry, %s is not a valid help type.", valtype); mcp_mesg_init(&omsg, "org-fuzzball-help", "error"); mcp_mesg_arg_append(&omsg, "text", buf); mcp_mesg_arg_append(&omsg, "topic", onwhat); mcp_frame_output_mesg(mfr, &omsg); mcp_mesg_clear(&omsg); return; } if ((f = fopen(file, "r")) == NULL) { snprintf(buf, sizeof(buf), "Sorry, %s is missing. Management has been notified.", file); fprintf(stderr, "help: No file %s!\n", file); mcp_mesg_init(&omsg, "org-fuzzball-help", "error"); mcp_mesg_arg_append(&omsg, "text", buf); mcp_mesg_arg_append(&omsg, "topic", onwhat); mcp_frame_output_mesg(mfr, &omsg); mcp_mesg_clear(&omsg); } else { if (*topic) { arglen = strlen(topic); do { do { if (!(fgets(buf, sizeof buf, f))) { snprintf(buf, sizeof(buf), "Sorry, no help available on topic \"%s\"", onwhat); fclose(f); mcp_mesg_init(&omsg, "org-fuzzball-help", "error"); mcp_mesg_arg_append(&omsg, "text", buf); mcp_mesg_arg_append(&omsg, "topic", onwhat); mcp_frame_output_mesg(mfr, &omsg); mcp_mesg_clear(&omsg); return; } } while (*buf != '~'); do { if (!(fgets(buf, sizeof buf, f))) { snprintf(buf, sizeof(buf), "Sorry, no help available on topic \"%s\"", onwhat); fclose(f); mcp_mesg_init(&omsg, "org-fuzzball-help", "error"); mcp_mesg_arg_append(&omsg, "text", buf); mcp_mesg_arg_append(&omsg, "topic", onwhat); mcp_frame_output_mesg(mfr, &omsg); mcp_mesg_clear(&omsg); return; } } while (*buf == '~'); p = buf; found = 0; buf[strlen(buf) - 1] = '|'; while (*p && !found) { if (strncasecmp(p, topic, arglen)) { while (*p && (*p != '|')) p++; if (*p) p++; } else { found = 1; } } } while (!found); } mcp_mesg_init(&omsg, "org-fuzzball-help", "entry"); mcp_mesg_arg_append(&omsg, "topic", onwhat); while (fgets(buf, sizeof buf, f)) { if (*buf == '~') break; for (p = buf; *p; p++) { if (*p == '\n' || *p == '\r') { *p = '\0'; break; } } if (!*buf) { strcpy(buf, " "); } mcp_mesg_arg_append(&omsg, "text", buf); } fclose(f); mcp_frame_output_mesg(mfr, &omsg); mcp_mesg_clear(&omsg); } } } #endif int show_subfile(dbref player, const char *dir, const char *topic, const char *seg, int partial) { char buf[256]; struct stat st; #ifdef DIR_AVALIBLE DIR *df; struct dirent *dp; #endif #ifdef WIN32 char *dirname; int dirnamelen = 0; HANDLE hFind; BOOL bMore; WIN32_FIND_DATA finddata; #endif if (!topic || !*topic) return 0; if ((*topic == '.') || (*topic == '~') || (index(topic, '/'))) { return 0; } if (strlen(topic) > 63) return 0; #ifdef DIR_AVALIBLE /* TO DO: (1) exact match, or (2) partial match, but unique */ *buf = 0; if ((df = (DIR *) opendir(dir))) { while ((dp = readdir(df))) { if ((partial && string_prefix(dp->d_name, topic)) || (!partial && !string_compare(dp->d_name, topic)) ) { snprintf(buf, sizeof(buf), "%s/%s", dir, dp->d_name); break; } } closedir(df); } if (!*buf) { return 0; /* no such file or directory */ } #elif WIN32 /* TO DO: (1) exact match, or (2) partial match, but unique */ *buf = 0; dirnamelen = strlen(dir) + 5; dirname = (char *) malloc(dirnamelen); strcpy(dirname, dir); strcatn(dirname, dirnamelen, "*.*"); hFind = FindFirstFile(dirname,&finddata); bMore = (hFind != (HANDLE) -1); free(dirname); while (bMore) { if (!(finddata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) { if ((partial && string_prefix(finddata.cFileName, topic)) || (!partial && !string_compare(finddata.cFileName,topic)) ) { snprintf(buf, sizeof(buf), "%s/%s", dir, finddata.cFileName); break; } } bMore = FindNextFile(hFind, &finddata); } #else /* !DIR_AVAILABLE && !WIN32 */ snprintf(buf, sizeof(buf), "%s/%s", dir, topic); #endif if (stat(buf, &st)) { return 0; } else { spit_file_segment(player, buf, seg); return 1; } } #if !defined(STANDALONE_HELP) void do_man(dbref player, char *topic, char *seg) { if (show_subfile(player, MAN_DIR, topic, seg, FALSE)) return; index_file(player, topic, MAN_FILE); } void do_mpihelp(dbref player, char *topic, char *seg) { if (show_subfile(player, MPI_DIR, topic, seg, FALSE)) return; index_file(player, topic, MPI_FILE); } void do_help(dbref player, char *topic, char *seg) { if (show_subfile(player, HELP_DIR, topic, seg, FALSE)) return; index_file(player, topic, HELP_FILE); } void do_news(dbref player, char *topic, char *seg) { if (show_subfile(player, NEWS_DIR, topic, seg, FALSE)) return; index_file(player, topic, NEWS_FILE); } void add_motd_text_fmt(const char *text) { char buf[80]; const char *p = text; int count = 4; buf[0] = buf[1] = buf[2] = buf[3] = ' '; while (*p) { while (*p && (count < 68)) buf[count++] = *p++; while (*p && !isspace(*p) && (count < 76)) buf[count++] = *p++; buf[count] = '\0'; log2file(MOTD_FILE, "%s", buf); while (*p && isspace(*p)) p++; count = 0; } } void do_motd(dbref player, char *text) { time_t lt; if (!*text || !Wizard(OWNER(player))) { spit_file(player, MOTD_FILE); return; } if (!string_compare(text, "clear")) { unlink(MOTD_FILE); log2file(MOTD_FILE, "%s %s", "- - - - - - - - - - - - - - - - - - -", "- - - - - - - - - - - - - - - - - - -"); notify(player, "MOTD cleared."); return; } lt = time(NULL); log2file(MOTD_FILE, "%.16s", ctime(<)); add_motd_text_fmt(text); log2file(MOTD_FILE, "%s %s", "- - - - - - - - - - - - - - - - - - -", "- - - - - - - - - - - - - - - - - - -"); notify(player, "MOTD updated."); } void do_info(dbref player, const char *topic, const char *seg) { char *buf; int f; int cols; int buflen = 80; #ifdef DIR_AVALIBLE DIR *df; struct dirent *dp; #endif #ifdef WIN32 HANDLE hFind; BOOL bMore; WIN32_FIND_DATA finddata; char *dirname; int dirnamelen = 0; #endif if (*topic) { if (!show_subfile(player, INFO_DIR, topic, seg, TRUE)) { notify(player, NO_INFO_MSG); } } else { #ifdef DIR_AVALIBLE buf = (char *) calloc(1, buflen); (void) strcpy(buf, " "); f = 0; cols = 0; if ((df = (DIR *) opendir(INFO_DIR))) { while ((dp = readdir(df))) { if (*(dp->d_name) != '.') { if (!f) notify(player, "Available information files are:"); if ((cols++ > 2) || ((strlen(buf) + strlen(dp->d_name)) > 63)) { notify(player, buf); strcpy(buf, " "); cols = 0; } strcatn(buf, buflen, dp->d_name); strcatn(buf, buflen, " "); f = strlen(buf); while ((f % 20) != 4) buf[f++] = ' '; buf[f] = '\0'; } } closedir(df); } if (f) notify(player, buf); else notify(player, "No information files are available."); free(buf); #elif WIN32 buf = (char *) calloc(1,buflen); (void) strcpy(buf, " "); f = 0; cols = 0; dirnamelen = strlen(INFO_DIR) + 4; dirname = (char *) malloc(dirnamelen); strcpy(dirname, INFO_DIR); strcatn(dirname, dirnamelen, "*.*"); hFind = FindFirstFile(dirname,&finddata); bMore = (hFind != (HANDLE) -1); free(dirname); while (bMore) { if (!(finddata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) { if (!f) notify(player, "Available information files are:"); if ((cols++ > 2) || ((strlen(buf) + strlen(finddata.cFileName)) > 63)) { notify(player,buf); (void) strcpy(buf, " "); cols = 0; } strcatn(buf, buflen, finddata.cFileName); strcatn(buf, buflen, " "); f = strlen(buf); while((f %20) != 4) buf[f++] = ' '; buf[f] = '\0'; } bMore = FindNextFile(hFind, &finddata); } if (f) notify(player, buf); else notify(player, "There are no information files available."); free(buf); #else /* !DIR_AVALIBLE && !WIN32 */ notify(player, "Index not available on this system."); #endif /* !DIR_AVALIBLE && !WIN32 */ } } #else /* STANDALONE_HELP */ int main(int argc, char**argv) { char* helpfile = NULL; char* topic = NULL; char buf[BUFFER_LEN]; if (argc < 2) { fprintf(stderr, "Usage: %s muf|mpi|help [topic]\n", argv[0]); exit(-1); } else if (argc == 2 || argc == 3) { if (argc == 2) { topic = ""; } else { topic = argv[2]; } if (!strcmp(argv[1], "man")) { helpfile = MAN_FILE; } else if (!strcmp(argv[1], "muf")) { helpfile = MAN_FILE; } else if (!strcmp(argv[1], "mpi")) { helpfile = MPI_FILE; } else if (!strcmp(argv[1], "help")) { helpfile = HELP_FILE; } else { fprintf(stderr, "Usage: %s muf|mpi|help [topic]\n", argv[0]); exit(-2); } helpfile = rindex(helpfile, '/'); helpfile++; #ifdef HELPFILE_DIR snprintf(buf, sizeof(buf), "%s/%s", HELPFILE_DIR, helpfile); #else snprintf(buf, sizeof(buf), "%s/%s", "/usr/local/fbmuck/help", helpfile); #endif index_file(1, topic, buf); exit(0); } else if (argc > 3) { fprintf(stderr, "Usage: %s muf|mpi|help [topic]\n", argv[0]); exit(-1); } return 0; } #endif /* STANDALONE_HELP */