From 0baa7d866d154860892889c72eb6d98efff6efe5 Mon Sep 17 00:00:00 2001 From: John Reese Date: Thu, 13 Jan 2011 16:26:31 -0500 Subject: [PATCH] Proof of concept completed User can set and retrieve config values for their Notifo account name and API secret. The SEND command allows the user to send an arbitrary notification to their account. Fixed issue with encoding credentials in request headers. Tested against official API and notification succeeded. --- notifo.cpp | 185 ++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 161 insertions(+), 24 deletions(-) diff --git a/notifo.cpp b/notifo.cpp index 2ecea7d..de796e3 100644 --- a/notifo.cpp +++ b/notifo.cpp @@ -19,54 +19,191 @@ #error This module needs ZNC 0.072 or newer. #endif +#define DEBUG_HOST 0 +#define DEBUG_LOGGING 0 + class CNotifoMod : public CModule { + protected: + + // Too lazy to add CString("\r\n\") everywhere + CString crlf; + + // Host and URL to send messages to + CString notifo_host; + CString notifo_url; + + // User agent to use + CString user_agent; + + // Recipient account's username and API secret + CString notifo_username; + CString notifo_secret; + public: - MODCONSTRUCTOR(CNotifoMod) {} + + MODCONSTRUCTOR(CNotifoMod) { + crlf = "\r\n"; + +#if DEBUG_HOST + notifo_host = "notifo.leetcode.net"; + notifo_url = "/index.php"; +#else + notifo_host = "api.notifo.com"; + notifo_url = "/v1/send_notification"; +#endif + + user_agent = "ZNC To Notifo"; + + notifo_username = ""; + notifo_secret = ""; + } virtual ~CNotifoMod() {} - virtual void OnModCommand(const CString& sCommand) - { - PutModule("Sending message..."); - sendmessage("foo"); - } - protected: + + /** + * Shorthand for encoding a string for a URL. + * + * @param str String to be encoded + * @return Encoded string + */ CString urlencode(const CString& str) { return str.Escape_n(CString::EASCII, CString::EURL); } - void sendmessage(const CString& message) + /** + * Send a message to the currently-configured Notifo account. + * Requires (and assumes) that the user has already configured their + * username and API secret using the 'set' command. + * + * @param message Message to be sent to the user + */ + void send_message(const CString& message) { - CString crlf = "\r\n"; + // BASIC auth style + CString auth = notifo_username + CString(":") + notifo_secret; - CString auth = "foo:bar"; - - CString post = "to="; + // POST body parameters for the request + CString post = "to=" + urlencode(notifo_username); post += "&msg=" + urlencode(message); post += "&label=" + urlencode(CString("ZNC")); post += "&title=" + urlencode(CString("New Message")); - post += "&uri="; + post += "&uri=" + urlencode(CString("http://notifo.leetcode.net/")); - CString headers = "POST /index.php HTTP/1.1" + crlf; - headers += "Host: notifo.leetcode.net" + crlf; - headers += "Content-Type: application/x-www-form-urlencoded" + crlf; - headers += "Content-Length: " + CString(post.length()) + crlf; - headers += "User-Agent: zncnotifo" + crlf; - headers += "Authorization: Basic " + auth.Base64Encode() + crlf; - headers += crlf; - headers += post + crlf; + // Request headers and POST body + CString request = "POST " + notifo_url + " HTTP/1.1" + crlf; + request += "Host: " + notifo_host + crlf; + request += "Content-Type: application/x-www-form-urlencoded" + crlf; + request += "Content-Length: " + CString(post.length()) + crlf; + request += "User-Agent: " + user_agent + crlf; + request += "Authorization: Basic " + auth.Base64Encode_n() + crlf; + request += crlf; + request += post + crlf; + // Create the socket connection, write to it, and add it to the queue CSocket *sock = new CSocket(this); - sock->Connect("notifo.leetcode.net", 443, true); - sock->Write(headers); + sock->Connect(notifo_host, 443, true); + sock->Write(request); sock->Close(Csock::CLT_AFTERWRITE); AddSocket(sock); +#if DEBUG_LOGGING + // Log the HTTP request FILE *fh = fopen("/tmp/notifo.log", "a"); - fputs(headers.c_str(), fh); + fputs(request.c_str(), fh); fclose(fh); +#endif + } + + protected: + + bool OnLoad(const CString& args, CString& message) + { + notifo_username = GetNV("notifo_username"); + notifo_secret = GetNV("notifo_secret"); + + return true; + } + + /** + * Handle direct commands to the *notifo virtual user. + * + * @param command Command string + */ + void OnModCommand(const CString& command) + { + VCString tokens; + int token_count = command.Split(" ", tokens, false); + + CString action = tokens[0].AsLower(); + + // SET command + if (action == "set") + { + if (token_count != 3) + { + PutModule("Usage: set