From 9e1c25a889d7a18c1df7f13da64dc38e1a3a9eec Mon Sep 17 00:00:00 2001 From: Alexander Barton Date: Mon, 31 Dec 2012 19:26:31 +0100 Subject: Refactor Read_Motd() into Read_TextFile() Now this function allows to read arbitrary text files into arrays. --- src/ngircd/conf.c | 41 ++++++++++++++++++++++++----------------- 1 file changed, 24 insertions(+), 17 deletions(-) (limited to 'src') diff --git a/src/ngircd/conf.c b/src/ngircd/conf.c index bea4d619..423221cb 100644 --- a/src/ngircd/conf.c +++ b/src/ngircd/conf.c @@ -784,39 +784,44 @@ no_listenports(void) } /** - * Read MOTD ("message of the day") file. + * Read contents of a text file into an array. + * + * This function is used to read the MOTD and help text file, for exampe. * * @param filename Name of the file to read. + * @return true, when the file has been read in. */ -static void -Read_Motd(const char *filename) +static bool +Read_TextFile(const char *Filename, const char *Name, array *Destination) { char line[127]; FILE *fp; + int line_no = 1; - if (*filename == '\0') - return; + if (*Filename == '\0') + return false; - fp = fopen(filename, "r"); + fp = fopen(Filename, "r"); if (!fp) { - Config_Error(LOG_WARNING, "Can't read MOTD file \"%s\": %s", - filename, strerror(errno)); - return; + Config_Error(LOG_WARNING, "Can't read %s file \"%s\": %s", + Name, Filename, strerror(errno)); + return false; } - array_free(&Conf_Motd); - Using_MotdFile = true; - + array_free(Destination); while (fgets(line, (int)sizeof line, fp)) { - ngt_TrimLastChr( line, '\n'); + ngt_TrimLastChr(line, '\n'); /* add text including \0 */ - if (!array_catb(&Conf_Motd, line, strlen(line) + 1)) { - Log(LOG_WARNING, "Cannot add MOTD text: %s", strerror(errno)); + if (!array_catb(Destination, line, strlen(line) + 1)) { + Log(LOG_WARNING, "Cannot read/add \"%s\", line %d: %s", + Filename, line_no, strerror(errno)); break; } + line_no++; } fclose(fp); + return true; } /** @@ -1037,8 +1042,10 @@ Read_Config(bool TestOnly, bool IsStarting) } /* No MOTD phrase configured? (re)try motd file. */ - if (array_bytes(&Conf_Motd) == 0) - Read_Motd(Conf_MotdFile); + if (array_bytes(&Conf_Motd) == 0) { + if (Read_TextFile(Conf_MotdFile, "MOTD", &Conf_Motd)) + Using_MotdFile = true; + } #ifdef SSL_SUPPORT /* Make sure that all SSL-related files are readable */ -- cgit 1.4.1 From 588af510a35b5b28cb8c1063ac865f86c65d7a8a Mon Sep 17 00:00:00 2001 From: Alexander Barton Date: Mon, 31 Dec 2012 19:27:32 +0100 Subject: IRC_HELP(): Code cleanup --- src/ngircd/irc.c | 30 ++++++++++++++++++++---------- 1 file changed, 20 insertions(+), 10 deletions(-) (limited to 'src') diff --git a/src/ngircd/irc.c b/src/ngircd/irc.c index 63c4813a..1a0d725f 100644 --- a/src/ngircd/irc.c +++ b/src/ngircd/irc.c @@ -304,25 +304,35 @@ IRC_TRACE( CLIENT *Client, REQUEST *Req ) } /* IRC_TRACE */ +/** + * Handler for the IRC "HELP" command. + * + * @param Client The client from which this command has been received. + * @param Req Request structure with prefix and all parameters. + * @return CONNECTED or DISCONNECTED. + */ GLOBAL bool -IRC_HELP( CLIENT *Client, REQUEST *Req ) +IRC_HELP(CLIENT *Client, REQUEST *Req) { COMMAND *cmd; - assert( Client != NULL ); - assert( Req != NULL ); + assert(Client != NULL); + assert(Req != NULL); /* Bad number of arguments? */ - if( Req->argc > 0 ) return IRC_WriteStrClient( Client, ERR_NORECIPIENT_MSG, Client_ID( Client ), Req->command ); + if (Req->argc > 0) + return IRC_WriteStrClient(Client, ERR_NORECIPIENT_MSG, + Client_ID(Client), Req->command); - cmd = Parse_GetCommandStruct( ); - while( cmd->name ) - { - if( ! IRC_WriteStrClient( Client, "NOTICE %s :%s", Client_ID( Client ), cmd->name )) return DISCONNECTED; + cmd = Parse_GetCommandStruct(); + while(cmd->name) { + if (!IRC_WriteStrClient(Client, "NOTICE %s :%s", + Client_ID(Client), cmd->name)) + return DISCONNECTED; cmd++; } - - IRC_SetPenalty( Client, 2 ); + + IRC_SetPenalty(Client, 2); return CONNECTED; } /* IRC_HELP */ -- cgit 1.4.1 From f68aa02272d05ffbceea9e0188984d9bf9b83dd1 Mon Sep 17 00:00:00 2001 From: Alexander Barton Date: Mon, 31 Dec 2012 19:29:52 +0100 Subject: Implement new configuration option "HelpFile" This new configuration option allows to specify a specially formatted text file which can be used by the HELP command to provide information about the commands and their syntaxes. --- src/ngircd/conf.c | 17 +++++++++++++++++ src/ngircd/conf.h | 3 +++ src/ngircd/defines.h | 3 +++ 3 files changed, 23 insertions(+) (limited to 'src') diff --git a/src/ngircd/conf.c b/src/ngircd/conf.c index 423221cb..fa1bfba1 100644 --- a/src/ngircd/conf.c +++ b/src/ngircd/conf.c @@ -54,6 +54,7 @@ static CONF_SERVER New_Server; static int New_Server_Idx; static char Conf_MotdFile[FNAME_LEN]; +static char Conf_HelpFile[FNAME_LEN]; static void Set_Defaults PARAMS(( bool InitServers )); static bool Read_Config PARAMS(( bool TestOnly, bool IsStarting )); @@ -316,6 +317,7 @@ Conf_Test( void ) printf(" AdminInfo1 = %s\n", Conf_ServerAdmin1); printf(" AdminInfo2 = %s\n", Conf_ServerAdmin2); printf(" AdminEMail = %s\n", Conf_ServerAdminMail); + printf(" HelpFile = %s\n", Conf_HelpFile); printf(" Info = %s\n", Conf_ServerInfo); printf(" Listen = %s\n", Conf_ListenAddress); if (Using_MotdFile) { @@ -701,8 +703,11 @@ Set_Defaults(bool InitServers) Conf_ListenAddress = NULL; array_free(&Conf_ListenPorts); array_free(&Conf_Motd); + array_free(&Conf_Helptext); strlcpy(Conf_MotdFile, SYSCONFDIR, sizeof(Conf_MotdFile)); strlcat(Conf_MotdFile, MOTD_FILE, sizeof(Conf_MotdFile)); + strlcpy(Conf_HelpFile, SYSCONFDIR, sizeof(Conf_HelpFile)); + strlcat(Conf_HelpFile, HELP_FILE, sizeof(Conf_HelpFile)); strcpy(Conf_ServerPwd, ""); strlcpy(Conf_PidFile, PID_FILE, sizeof(Conf_PidFile)); Conf_UID = Conf_GID = 0; @@ -1047,6 +1052,12 @@ Read_Config(bool TestOnly, bool IsStarting) Using_MotdFile = true; } + /* Try to read ngIRCd help text file. */ + (void)Read_TextFile(Conf_HelpFile, "help text", &Conf_Helptext); + if (!array_bytes(&Conf_Helptext)) + Config_Error(LOG_WARNING, + "No help text available, HELP command will be of limited use."); + #ifdef SSL_SUPPORT /* Make sure that all SSL-related files are readable */ CheckFileReadable("CertFile", Conf_SSLOptions.CertFile); @@ -1312,6 +1323,12 @@ Handle_GLOBAL( int Line, char *Var, char *Arg ) Config_Error_TooLong(Line, Var); return; } + if (strcasecmp(Var, "HelpFile") == 0) { + len = strlcpy(Conf_HelpFile, Arg, sizeof(Conf_HelpFile)); + if (len >= sizeof(Conf_HelpFile)) + Config_Error_TooLong(Line, Var); + return; + } if (strcasecmp(Var, "Listen") == 0) { if (Conf_ListenAddress) { Config_Error(LOG_ERR, diff --git a/src/ngircd/conf.h b/src/ngircd/conf.h index f85a25fa..ac42746c 100644 --- a/src/ngircd/conf.h +++ b/src/ngircd/conf.h @@ -111,6 +111,9 @@ GLOBAL char Conf_ServerAdminMail[CLIENT_INFO_LEN]; /** Message of the day (MOTD) of this server */ GLOBAL array Conf_Motd; +/** Help text of this server */ +GLOBAL array Conf_Helptext; + /** Array of ports this server should listen on */ GLOBAL array Conf_ListenPorts; diff --git a/src/ngircd/defines.h b/src/ngircd/defines.h index ad9716fd..28a260b8 100644 --- a/src/ngircd/defines.h +++ b/src/ngircd/defines.h @@ -77,6 +77,9 @@ /** Name of the MOTD file. */ #define MOTD_FILE "/ngircd.motd" +/** Name of the help file. */ +#define HELP_FILE "/ngircd.help" + /** Default chroot() directory. */ #define CHROOT_DIR "" -- cgit 1.4.1 From 289a26e9e43be303a7355ab530ddcaa84aca60b9 Mon Sep 17 00:00:00 2001 From: Alexander Barton Date: Tue, 1 Jan 2013 14:57:03 +0100 Subject: Implement Help() function parsing and returning the help text This function parses the already read in help text and sends the requested portions to the user. Parsing is done as following when a user user issues a "HELP " command: 1. Search the file for a line "- ", 2. Output all subsequent lines that start with a TAB (ASCII 9) character to the client using NOTICE commands, treat lines containing a single "." after the TAB as empty lines. 3. Break at the first line not starting with a TAB character. This format allows to have information to each command stored in this file which will not be sent to an IRC user requesting help which enables us to have additional annotations stored here which further describe the origin, implementation details, or limits of the specific command. A special "Intro" block is returned to the user when the HELP command is used without a command name. --- src/ngircd/irc.c | 84 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 81 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/ngircd/irc.c b/src/ngircd/irc.c index 1a0d725f..f6b9dc59 100644 --- a/src/ngircd/irc.c +++ b/src/ngircd/irc.c @@ -44,6 +44,7 @@ static bool Send_Message PARAMS((CLIENT *Client, REQUEST *Req, int ForceType, static bool Send_Message_Mask PARAMS((CLIENT *from, char *command, char *targetMask, char *message, bool SendErrors)); +static bool Help PARAMS((CLIENT *Client, const char *Topic)); /** @@ -320,10 +321,23 @@ IRC_HELP(CLIENT *Client, REQUEST *Req) assert(Req != NULL); /* Bad number of arguments? */ - if (Req->argc > 0) + if (Req->argc > 1) return IRC_WriteStrClient(Client, ERR_NORECIPIENT_MSG, Client_ID(Client), Req->command); + IRC_SetPenalty(Client, 2); + + if ((Req->argc == 0 && array_bytes(&Conf_Helptext) > 0) + || (Req->argc >= 1 && strcasecmp(Req->argv[0], "Commands") != 0)) { + /* Help text available and requested */ + if (Req->argc >= 1) + return Help(Client, Req->argv[0]); + + if (!Help(Client, "Intro")) + return DISCONNECTED; + return CONNECTED; + } + cmd = Parse_GetCommandStruct(); while(cmd->name) { if (!IRC_WriteStrClient(Client, "NOTICE %s :%s", @@ -331,12 +345,76 @@ IRC_HELP(CLIENT *Client, REQUEST *Req) return DISCONNECTED; cmd++; } - - IRC_SetPenalty(Client, 2); return CONNECTED; } /* IRC_HELP */ +/** + * Send help for a given topic to the client. + * + * @param Client The client requesting help. + * @param Topoc The help topic requested. + * @return CONNECTED or DISCONNECTED. + */ +static bool +Help(CLIENT *Client, const char *Topic) +{ + char *line; + size_t helptext_len, len_str, idx_start, lines = 0; + bool in_article = false; + + assert(Client != NULL); + assert(Topic != NULL); + + helptext_len = array_bytes(&Conf_Helptext); + line = array_start(&Conf_Helptext); + while (helptext_len > 0) { + len_str = strlen(line) + 1; + assert(helptext_len >= len_str); + helptext_len -= len_str; + + if (in_article) { + /* The first character in each article text line must + * be a TAB (ASCII 9) character which will be stripped + * in the output. If it is not a TAB, the end of the + * article has been reached. */ + if (line[0] != '\t') { + if (lines > 0) + return CONNECTED; + else + break; + } + + /* A single '.' character indicates an empty line */ + if (line[1] == '.' && line[2] == '\0') + idx_start = 2; + else + idx_start = 1; + + if (!IRC_WriteStrClient(Client, "NOTICE %s :%s", + Client_ID(Client), + &line[idx_start])) + return DISCONNECTED; + lines++; + + } else { + if (line[0] == '-' && line[1] == ' ' + && strcasecmp(&line[2], Topic) == 0) + in_article = true; + } + + line += len_str; + } + + /* Help topic not found (or empty)! */ + if (!IRC_WriteStrClient(Client, "NOTICE %s :No help for \"%s\" found!", + Client_ID(Client), Topic)) + return DISCONNECTED; + + return CONNECTED; +} + + static char * #ifdef ZLIB Option_String(CONN_ID Idx) -- cgit 1.4.1 From 950aeec3ff0e15c456ac32d8fecee8c73f7c5df3 Mon Sep 17 00:00:00 2001 From: Alexander Barton Date: Tue, 1 Jan 2013 19:25:06 +0100 Subject: Use "${docdir}/Commands.txt" as help text file --- configure.ng | 4 ++-- contrib/MacOSX/config.h | 3 ++- doc/Makefile.am | 3 ++- doc/sample-ngircd.conf.tmpl | 2 +- src/ngircd/conf.c | 4 ++-- src/ngircd/defines.h | 2 +- 6 files changed, 10 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/configure.ng b/configure.ng index 84e27508..732e55ee 100644 --- a/configure.ng +++ b/configure.ng @@ -1,6 +1,6 @@ # # ngIRCd -- The Next Generation IRC Daemon -# Copyright (c)2001-2012 Alexander Barton (alex@barton.de) and Contributors +# Copyright (c)2001-2013 Alexander Barton (alex@barton.de) and Contributors # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -110,7 +110,7 @@ esac # Add additional CFLAGS, eventually specified on the command line: test -n "$CFLAGS_ADD" && CFLAGS="$CFLAGS $CFLAGS_ADD" -CFLAGS="$CFLAGS -DSYSCONFDIR='\"\$(sysconfdir)\"'" +CFLAGS="$CFLAGS -DSYSCONFDIR='\"\$(sysconfdir)\"' -DDOCDIR='\"\$(docdir)\"'" # -- Headers -- diff --git a/contrib/MacOSX/config.h b/contrib/MacOSX/config.h index 6da74962..f4838276 100644 --- a/contrib/MacOSX/config.h +++ b/contrib/MacOSX/config.h @@ -1,6 +1,6 @@ /* * ngIRCd -- The Next Generation IRC Daemon - * Copyright (c)2001-2012 Alexander Barton (alex@barton.de) and Contributors. + * Copyright (c)2001-2013 Alexander Barton (alex@barton.de) and Contributors. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -17,6 +17,7 @@ #define VERSION "??("__DATE__")" #endif #define SYSCONFDIR "/etc/ngircd" +#define DOCDIR "/usr/share/doc/ngircd" #ifndef TARGET_VENDOR #define TARGET_VENDOR "apple" diff --git a/doc/Makefile.am b/doc/Makefile.am index eb6fa937..04f74b60 100644 --- a/doc/Makefile.am +++ b/doc/Makefile.am @@ -1,6 +1,6 @@ # # ngIRCd -- The Next Generation IRC Daemon -# Copyright (c)2001-2012 Alexander Barton (alex@barton.de) and Contributors +# Copyright (c)2001-2013 Alexander Barton (alex@barton.de) and Contributors # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -12,6 +12,7 @@ .tmpl: $(AM_V_GEN)sed \ -e "s@:ETCDIR:@${sysconfdir}@" \ + -e "s@:DOCDIR:@${docdir}@" \ <$< >$@ SUFFIXES = .tmpl diff --git a/doc/sample-ngircd.conf.tmpl b/doc/sample-ngircd.conf.tmpl index 3f80a9f9..1c3998ad 100644 --- a/doc/sample-ngircd.conf.tmpl +++ b/doc/sample-ngircd.conf.tmpl @@ -35,7 +35,7 @@ # Text file which contains the ngIRCd help text. This file is required # to display help texts when using the "HELP " command. - ;HelpFile = :ETCDIR:/ngircd.help + ;HelpFile = :DOCDIR:/Commands.txt # Info text of the server. This will be shown by WHOIS and # LINKS requests for example. diff --git a/src/ngircd/conf.c b/src/ngircd/conf.c index fa1bfba1..d5a28bd7 100644 --- a/src/ngircd/conf.c +++ b/src/ngircd/conf.c @@ -1,6 +1,6 @@ /* * ngIRCd -- The Next Generation IRC Daemon - * Copyright (c)2001-2012 Alexander Barton (alex@barton.de) and Contributors. + * Copyright (c)2001-2013 Alexander Barton (alex@barton.de) and Contributors. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -706,7 +706,7 @@ Set_Defaults(bool InitServers) array_free(&Conf_Helptext); strlcpy(Conf_MotdFile, SYSCONFDIR, sizeof(Conf_MotdFile)); strlcat(Conf_MotdFile, MOTD_FILE, sizeof(Conf_MotdFile)); - strlcpy(Conf_HelpFile, SYSCONFDIR, sizeof(Conf_HelpFile)); + strlcpy(Conf_HelpFile, DOCDIR, sizeof(Conf_HelpFile)); strlcat(Conf_HelpFile, HELP_FILE, sizeof(Conf_HelpFile)); strcpy(Conf_ServerPwd, ""); strlcpy(Conf_PidFile, PID_FILE, sizeof(Conf_PidFile)); diff --git a/src/ngircd/defines.h b/src/ngircd/defines.h index 28a260b8..3850b581 100644 --- a/src/ngircd/defines.h +++ b/src/ngircd/defines.h @@ -78,7 +78,7 @@ #define MOTD_FILE "/ngircd.motd" /** Name of the help file. */ -#define HELP_FILE "/ngircd.help" +#define HELP_FILE "/Commands.txt" /** Default chroot() directory. */ #define CHROOT_DIR "" -- cgit 1.4.1