]> arthur.barton.de Git - ngircd-alex.git/commitdiff
Merge branch 'bug145-ProvideHelp'
authorAlexander Barton <alex@barton.de>
Wed, 2 Jan 2013 22:41:46 +0000 (23:41 +0100)
committerAlexander Barton <alex@barton.de>
Wed, 2 Jan 2013 22:41:46 +0000 (23:41 +0100)
* bug145-ProvideHelp:
  Use "${docdir}/Commands.txt" as help text file
  Add a note that "help file" is updated on startup and REHASH only
  Add doc/Commands.txt which should document all commands
  Implement Help() function parsing and returning the help text
  Document "HelpFile" in sample-ngircd.conf and ngircd.conf.5
  Implement new configuration option "HelpFile"
  IRC_HELP(): Code cleanup
  Refactor Read_Motd() into Read_TextFile()

configure.ng
contrib/MacOSX/config.h
doc/Commands.txt [new file with mode: 0644]
doc/Makefile.am
doc/sample-ngircd.conf.tmpl
man/ngircd.conf.5.tmpl
src/ngircd/conf.c
src/ngircd/conf.h
src/ngircd/defines.h
src/ngircd/irc.c

index 84e27508c793721cade924c8ee25f743affbddcd..732e55ee01388280e2e858a86b686dee0826dbb4 100644 (file)
@@ -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 --
 
index 6da74962c5551f56c32a456f3ecd7aace23d6998..f4838276ecfddcb8bccd5a42b7fb1fc410d64a5d 100644 (file)
@@ -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/Commands.txt b/doc/Commands.txt
new file mode 100644 (file)
index 0000000..e9b7873
--- /dev/null
@@ -0,0 +1,219 @@
+
+                     ngIRCd - Next Generation IRC Server
+                           http://ngircd.barton.de/
+
+               (c)2001-2013 Alexander Barton and Contributors.
+               ngIRCd is free software and published under the
+                   terms of the GNU General Public License.
+
+                              -- Commands.txt --
+
+
+This file lists all commands available on ngIRCd. It is written in a format
+that is human readable as well as machine parseable and therefore can be used
+as "help text file" of the daemon.
+
+In short, the HELP command parses this file as following when a user user
+issues a "HELP <cmd>" command:
+
+ 1. Search the file for a line "- <cmd>",
+ 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:
+
+
+- Intro
+       This is ngIRCd, a server software for Internet Relay Chat (IRC)
+       networks. You can find more information about ngIRCd on its homepage:
+               <http://ngircd.barton.de>
+       .
+       Use "HELP COMMANDS" to get a list of all available commands and
+       "HELP <command-name>" to get help for a specific IRC command, for
+       example "HELP quit" or "HELP privmsg".
+
+
+General Commands
+~~~~~~~~~~~~~~~~
+
+- AWAY
+
+- CAP
+
+- CHARCONV
+
+- HELP
+       HELP [<command>]
+       .
+       Show help information for a specific IRC <command>. The <command> name
+       is case-insensitive.
+       .
+       Use the command "HELP Commands" to get a list of all available commands.
+
+       The HELP command isn't specified by any RFC but implemented by most
+       daemons. If no help text could be read in, ngIRCd outputs a list of all
+       implemented commands when receiving a plain "HELP" command as well as
+       on "HELP Commands".
+
+       ngIRCd replies using "NOTICE" commands like ircd 2.10/2.11; other
+       implementations are using numerics 704, 705, and 706.
+
+
+- MODE
+
+- NICK
+
+- NOTICE
+
+- PASS
+
+- PING
+
+- PONG
+
+- PRIVMSG
+
+- QUIT
+       QUIT [<quit-message>]
+       .
+       End IRC session and disconnect from the server.
+       .
+       If a <quit-message> has been given, it is displayed to all the
+       channels that you are a member of when leaving.
+
+- USER
+
+- WALLOPS
+
+- WEBIRC
+
+
+Status and Informational Commands
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+- INFO
+
+- ISON
+
+- LINKS
+
+- LUSERS
+
+- METADATA
+
+- MOTD
+
+- NAMES
+
+- STATS
+
+- TIME
+
+- TRACE
+
+- USERHOST
+
+- VERSION
+
+- WHO
+
+- WHOIS
+
+- WHOWAS
+
+
+Channel Commands
+~~~~~~~~~~~~~~~~
+
+- INVITE
+
+- JOIN
+
+- KICK
+
+- LIST
+
+- PART
+
+- TOPIC
+
+
+Administrative Commands
+~~~~~~~~~~~~~~~~~~~~~~~
+
+- ADMIN
+       ADMIN [<server>]
+       .
+       Show administartive information about an IRC server in the network.
+       If no server name has been given, the local server will respond.
+
+- CONNECT
+
+- DIE
+
+- DISCONNECT
+
+- GLINE
+
+- KILL
+
+- KLINE
+
+- OPER
+
+- REHASH
+
+- RESTART
+
+
+IRC Service Commands
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+- SERVICE
+
+- SERVLIST
+
+- SQUERY
+
+- SVSNICK
+
+
+Server Protocol Commands
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+- CHANINFO
+
+- ERROR
+       ERROR [<message> [<> [...]]]
+       .
+       Return an error message to the server. The first parameter, if given,
+       will be logged by the server, all further parameters are silently
+       ignored.
+       .
+       This command is silently ignored on non-server and non-service links.
+
+- NJOIN
+
+- SERVER
+
+- SQUIT
+
+
+Dummy Commands
+~~~~~~~~~~~~~~
+
+- SUMMON
+
+- USERS
+
+- GET
+
+- POST
index 2b9b3aab5318a30cc4c1c398ec205ae93d4d0e87..04f74b6059acd132336f5527477d533297c6989a 100644 (file)
@@ -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
@@ -19,6 +20,7 @@ SUFFIXES = .tmpl
 static_docs = \
        Bopm.txt \
        Capabilities.txt \
+       Commands.txt \
        Contributing.txt \
        FAQ.txt \
        GIT.txt \
index 997a983d2bc08fbeb9bc9b2250bd487c631e779d..1c3998ad61368fca9448013206c2cd35e5187779 100644 (file)
        ;AdminInfo2 = Location
        ;AdminEMail = admin@irc.server
 
+       # Text file which contains the ngIRCd help text. This file is required
+       # to display help texts when using the "HELP <cmd>" command.
+       ;HelpFile = :DOCDIR:/Commands.txt
+
        # Info text of the server. This will be shown by WHOIS and
        # LINKS requests for example.
        Info = Server Info Text
index e3f62c84ceb3432a64410cf65e5f6df83961115e..859c6a8ac0eb547b915e73fbed78cbf4e726c8a5 100644 (file)
@@ -101,6 +101,12 @@ IRC network and must contain at least one dot (".") character.
 Information about the server and the administrator, used by the ADMIN
 command. This information is not required by the server but by RFC!
 .TP
+\fBHelpFile\fR (string)
+Text file which contains the ngIRCd help text. This file is required
+to display help texts when using the "HELP <cmd>" command.
+Please note: Changes made to this file take effect when ngircd starts up
+or is instructed to re-read its configuration file.
+.TP
 \fBInfo\fR (string)
 Info text of the server. This will be shown by WHOIS and LINKS requests for
 example.
index bea4d619a8c967f8a0e6ae18de8a767000da7af8..d5a28bd7bfbe25ab3b8268781236edfe663954f2 100644 (file)
@@ -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
@@ -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, DOCDIR, 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;
@@ -784,39 +789,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 +1047,16 @@ 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;
+       }
+
+       /* 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 */
@@ -1305,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,
index f85a25fa08920a2945c02603d2c8d05cc0dde086..ac42746c3a6872202435084bb55eaae544b7709f 100644 (file)
@@ -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;
 
index ad9716fdefb6f2e807d7567911df146f4a43bfd4..3850b5810a0c8ad67e379339207bfe45ada45b97 100644 (file)
@@ -77,6 +77,9 @@
 /** Name of the MOTD file. */
 #define MOTD_FILE "/ngircd.motd"
 
+/** Name of the help file. */
+#define HELP_FILE "/Commands.txt"
+
 /** Default chroot() directory. */
 #define CHROOT_DIR ""
 
index a678f9048e68d0c27b43d55533e333621d730543..e76abcb8a4af00250d819d00d332ca4a5cdc0f65 100644 (file)
@@ -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));
 
 
 /**
@@ -315,29 +316,116 @@ 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 > 1)
+               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;
+       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",
+                                       Client_ID(Client), cmd->name))
+                       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)