src/irc_conn.c
changeset 23 542c73d07d3c
parent 22 c339c020fd33
child 24 08a26d0b9afd
equal deleted inserted replaced
22:c339c020fd33 23:542c73d07d3c
     7 #include <string.h>
     7 #include <string.h>
     8 
     8 
     9 /*
     9 /*
    10  * "Welcome to the Internet Relay Network <nick>!<user>@<host>"
    10  * "Welcome to the Internet Relay Network <nick>!<user>@<host>"
    11  */
    11  */
    12 static void on_RPL_WELCOME (struct irc_conn *conn, const struct irc_line *line)
    12 static void on_RPL_WELCOME (struct irc_conn *conn, const struct irc_line *line, void *arg)
    13 {
    13 {
    14     // update state
    14     // update state
    15     conn->registered = true;
    15     conn->registered = true;
    16 
    16 
    17     log_info("registered");
    17     log_info("registered");
    20 /*
    20 /*
    21  * PING <server1> [ <server2> ]
    21  * PING <server1> [ <server2> ]
    22  *
    22  *
    23  * Send a 'PONG <server1>` reply right away.
    23  * Send a 'PONG <server1>` reply right away.
    24  */ 
    24  */ 
    25 static void on_PING (struct irc_conn *conn, const struct irc_line *line)
    25 static void on_PING (struct irc_conn *conn, const struct irc_line *line, void *arg)
    26 {
    26 {
    27     // just reply
    27     // just reply
    28     irc_conn_PONG(conn, line->args[0]);
    28     irc_conn_PONG(conn, line->args[0]);
    29 }
    29 }
    30 
    30 
    31 /*
    31 /*
    32  * Our command handlers
    32  * Our command handlers
    33  */
    33  */
    34 struct irc_cmd_handler {
    34 struct irc_cmd_handler _cmd_handlers[] = {
    35     /* The command name */
       
    36     const char *command;
       
    37 
       
    38     /* The handler function */
       
    39     void (*func) (struct irc_conn *conn, const struct irc_line *line);
       
    40 
       
    41 } _cmd_handlers[] = {
       
    42     { IRC_RPL_WELCOME,  on_RPL_WELCOME      },
    35     { IRC_RPL_WELCOME,  on_RPL_WELCOME      },
    43     { "PING",           on_PING             },
    36     { "PING",           on_PING             },
    44     { NULL,             NULL,               },
    37     { NULL,             NULL,               },
    45 };
    38 };
    46 
    39 
       
    40 /*
       
    41  * Incoming line handler
       
    42  */
    47 void irc_conn_on_line (char *line_buf, void *arg) 
    43 void irc_conn_on_line (char *line_buf, void *arg) 
    48 {
    44 {
    49     struct irc_conn *conn = arg;
    45     struct irc_conn *conn = arg;
    50     struct irc_line line;
    46     struct irc_line line;
       
    47     struct irc_cmd_chain *chain;
    51     struct irc_cmd_handler *handler;
    48     struct irc_cmd_handler *handler;
    52     int err;
    49     int err;
    53     
    50     
    54     // log
    51     // log
    55     log_debug("%s", line_buf);
    52     log_debug("%s", line_buf);
    56 
    53 
    57     // parse
    54     // parse
    58     if ((err = irc_line_parse(&line, line_buf))) {
    55     if ((err = irc_line_parse(&line, line_buf))) {
    59         printf("!!! Invalid line: %s: %s\n", line_buf, error_name(err));
    56         log_warn("invalid line: %s: %s\n", line_buf, error_name(err));
    60         
       
    61         return;
    57         return;
    62     }
    58     }
       
    59     
       
    60     // run each handler chain
       
    61     STAILQ_FOREACH(chain, &conn->handlers, node) {
       
    62         // look up appropriate handler
       
    63         for (handler = chain->handlers; handler->command; handler++) {
       
    64             // the command is alpha-only, so normal case-insensitive cmp is fine
       
    65             if (strcasecmp(handler->command, line.command) == 0) {
       
    66                 // invoke the func
       
    67                 handler->func(conn, &line, chain->arg);
    63 
    68 
    64     // look up appropriate handler
    69                 // ...only one per chain
    65     for (handler = _cmd_handlers; handler->command; handler++) {
    70                 break;
    66         // the command is alpha-only, so normal case-insensitive cmp is fine
    71             }
    67         if (strcasecmp(handler->command, line.command) == 0) {
       
    68             // invoke the func
       
    69             handler->func(conn, &line);
       
    70             break;
       
    71         }
    72         }
    72     }
    73     }
    73 }
    74 }
    74 
    75 
    75 err_t irc_conn_create (struct irc_conn **conn_ptr, struct sock_stream *sock, const struct irc_conn_config *config, struct error_info *err)
    76 err_t irc_conn_create (struct irc_conn **conn_ptr, struct sock_stream *sock, const struct irc_conn_config *config, struct error_info *err)
    77     struct irc_conn *conn;
    78     struct irc_conn *conn;
    78 
    79 
    79     // alloc new state struct
    80     // alloc new state struct
    80     if ((conn = calloc(1, sizeof(struct irc_conn))) == NULL)
    81     if ((conn = calloc(1, sizeof(struct irc_conn))) == NULL)
    81         return SET_ERROR(err, ERR_CALLOC);
    82         return SET_ERROR(err, ERR_CALLOC);
       
    83 
       
    84     // initialize command handlers
       
    85     STAILQ_INIT(&conn->handlers);
       
    86     
       
    87     // add the core handlers 
       
    88     if ((ERROR_CODE(err) = irc_conn_register_handler_chain(conn, _cmd_handlers, NULL)))
       
    89         return ERROR_CODE(err);
    82 
    90 
    83     // create the line_proto, with our on_line handler
    91     // create the line_proto, with our on_line handler
    84     if (line_proto_create(&conn->lp, sock, IRC_LINE_MAX * 1.5, &irc_conn_on_line, conn, err))
    92     if (line_proto_create(&conn->lp, sock, IRC_LINE_MAX * 1.5, &irc_conn_on_line, conn, err))
    85         return ERROR_CODE(err);
    93         return ERROR_CODE(err);
    86 
    94 
    92         return ERROR_CODE(err);
   100         return ERROR_CODE(err);
    93 
   101 
    94     // ok
   102     // ok
    95     *conn_ptr = conn;
   103     *conn_ptr = conn;
    96 
   104 
       
   105     return SUCCESS;
       
   106 }
       
   107 
       
   108 err_t irc_conn_register_handler_chain (struct irc_conn *conn, struct irc_cmd_handler *handlers, void *arg)
       
   109 {
       
   110     struct irc_cmd_chain *item;
       
   111 
       
   112     // allocate the chain item
       
   113     if ((item = calloc(1, sizeof(*item))) == NULL)
       
   114         return ERR_CALLOC;
       
   115 
       
   116     // store
       
   117     item->handlers = handlers;
       
   118     item->arg = arg;
       
   119 
       
   120     // append
       
   121     STAILQ_INSERT_TAIL(&conn->handlers, item, node);
       
   122 
       
   123     // ok
    97     return SUCCESS;
   124     return SUCCESS;
    98 }
   125 }
    99 
   126 
   100 err_t irc_conn_send (struct irc_conn *conn, const struct irc_line *line)
   127 err_t irc_conn_send (struct irc_conn *conn, const struct irc_line *line)
   101 {
   128 {
   146     };
   173     };
   147 
   174 
   148     return irc_conn_send(conn, &line);
   175     return irc_conn_send(conn, &line);
   149 }
   176 }
   150 
   177 
       
   178 err_t irc_conn_JOIN (struct irc_conn *conn, const char *channel)
       
   179 {
       
   180     // JOIN ( <channel> *( "," <channel> ) [ <key> *( "," <key> ) ] ) / "0"
       
   181     struct irc_line line = {
       
   182         NULL, "JOIN", { channel, NULL }
       
   183     };
       
   184 
       
   185     return irc_conn_send(conn, &line);
       
   186 }
       
   187