X-Git-Url: https://git.toastfreeware.priv.at/gregoa/bti.git/blobdiff_plain/03c3babc14f229472896d7ba863ff100f7ea329d..35f9afd2df1cc9b633ec9eee01a3292dc7eb5ccd:/bti.c diff --git a/bti.c b/bti.c index d0b8054..fe4c6e2 100644 --- a/bti.c +++ b/bti.c @@ -1,6 +1,7 @@ /* * Copyright (C) 2008 Greg Kroah-Hartman * Copyright (C) 2009 Bart Trojanowski + * Copyright (C) 2009 Amir Mohammad Saied * * 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 the @@ -16,6 +17,8 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ +#define _GNU_SOURCE + #include #include #include @@ -35,7 +38,6 @@ #include #include #include -#include "bti_version.h" #define zalloc(size) calloc(size, 1) @@ -43,23 +45,26 @@ #define dbg(format, arg...) \ do { \ if (debug) \ - printf("%s: " format , __func__ , ## arg); \ + fprintf(stdout, "bti: %s: " format , __func__ , \ + ## arg); \ } while (0) static int debug; +static int verbose; enum host { - HOST_TWITTER = 0, + HOST_TWITTER = 0, HOST_IDENTICA = 1, + HOST_CUSTOM = 2 }; enum action { - ACTION_UPDATE = 0, + ACTION_UPDATE = 0, ACTION_FRIENDS = 1, - ACTION_USER = 2, + ACTION_USER = 2, ACTION_REPLIES = 4, - ACTION_PUBLIC = 8, + ACTION_PUBLIC = 8, ACTION_UNKNOWN = 16 }; @@ -72,6 +77,7 @@ struct session { char *homedir; char *logfile; char *user; + char *hosturl; int bash; int shrink_urls; int dry_run; @@ -89,7 +95,7 @@ struct bti_curl_buffer { static void display_help(void) { fprintf(stdout, "bti - send tweet to twitter or identi.ca\n"); - fprintf(stdout, "Version: " BTI_VERSION "\n"); + fprintf(stdout, "Version: " VERSION "\n"); fprintf(stdout, "Usage:\n"); fprintf(stdout, " bti [options]\n"); fprintf(stdout, "options are:\n"); @@ -103,15 +109,18 @@ static void display_help(void) fprintf(stdout, " --host HOST\n"); fprintf(stdout, " --logfile logfile\n"); fprintf(stdout, " --shrink-urls\n"); + fprintf(stdout, " --page PAGENUMBER\n"); fprintf(stdout, " --bash\n"); fprintf(stdout, " --debug\n"); + fprintf(stdout, " --verbose\n"); + fprintf(stdout, " --dry-run\n"); fprintf(stdout, " --version\n"); fprintf(stdout, " --help\n"); } static void display_version(void) { - fprintf(stdout, "bti - version %s\n", BTI_VERSION); + fprintf(stdout, "bti - version %s\n", VERSION); } static struct session *session_alloc(void) @@ -135,6 +144,7 @@ static void session_free(struct session *session) free(session->time); free(session->homedir); free(session->user); + free(session->hosturl); free(session); } @@ -166,17 +176,14 @@ static void bti_curl_buffer_free(struct bti_curl_buffer *buffer) free(buffer); } -static const char *twitter_user_url = "http://twitter.com/statuses/user_timeline/"; -static const char *twitter_update_url = "https://twitter.com/statuses/update.xml"; -static const char *twitter_public_url = "http://twitter.com/statuses/public_timeline.xml"; -static const char *twitter_friends_url = "https://twitter.com/statuses/friends_timeline.xml"; -static const char *twitter_replies_url = "http://twitter.com/statuses/replies.xml"; +static const char *twitter_host = "https://twitter.com/statuses"; +static const char *identica_host = "https://identi.ca/api/statuses"; -static const char *identica_user_url = "http://identi.ca/api/statuses/user_timeline/"; -static const char *identica_update_url = "http://identi.ca/api/statuses/update.xml"; -static const char *identica_public_url = "http://identi.ca/api/statuses/public_timeline.xml"; -static const char *identica_friends_url = "http://identi.ca/api/statuses/friends_timeline.xml"; -static const char *identica_replies_url = "http://identi.ca/api/statuses/replies.xml"; +static const char *user_uri = "/user_timeline/"; +static const char *update_uri = "/update.xml"; +static const char *public_uri = "/public_timeline.xml"; +static const char *friends_uri = "/friends_timeline.xml"; +static const char *replies_uri = "/replies.xml"; static CURL *curl_init(void) { @@ -193,15 +200,18 @@ static CURL *curl_init(void) return curl; } -void parse_statuses(xmlDocPtr doc, xmlNodePtr current) +static void parse_statuses(xmlDocPtr doc, xmlNodePtr current) { xmlChar *text = NULL; xmlChar *user = NULL; + xmlChar *created = NULL; xmlNodePtr userinfo; current = current->xmlChildrenNode; while (current != NULL) { if (current->type == XML_ELEMENT_NODE) { + if (!xmlStrcmp(current->name, (const xmlChar *)"created_at")) + created = xmlNodeListGetString(doc, current->xmlChildrenNode, 1); if (!xmlStrcmp(current->name, (const xmlChar *)"text")) text = xmlNodeListGetString(doc, current->xmlChildrenNode, 1); if (!xmlStrcmp(current->name, (const xmlChar *)"user")) { @@ -215,12 +225,20 @@ void parse_statuses(xmlDocPtr doc, xmlNodePtr current) userinfo = userinfo->next; } } - if (user && text) { - printf("[%s] %s\n", user, text); + + if (user && text && created) { + if (verbose) + printf("[%s] (%.16s) %s\n", + user, created, text); + else + printf("[%s] %s\n", + user, text); xmlFree(user); xmlFree(text); + xmlFree(created); user = NULL; text = NULL; + created = NULL; } } current = current->next; @@ -263,7 +281,8 @@ static void parse_timeline(char *document) return; } -size_t curl_callback(void *buffer, size_t size, size_t nmemb, void *userp) +static size_t curl_callback(void *buffer, size_t size, size_t nmemb, + void *userp) { struct bti_curl_buffer *curl_buf = userp; size_t buffer_size = size * nmemb; @@ -292,10 +311,9 @@ size_t curl_callback(void *buffer, size_t size, size_t nmemb, void *userp) static int send_request(struct session *session) { + char endpoint[100]; char user_password[500]; char data[500]; - /* is there usernames longer than 22 chars? */ - char user_url[70]; struct bti_curl_buffer *curl_buf; CURL *curl = NULL; CURLcode res; @@ -332,75 +350,38 @@ static int send_request(struct session *session) curl_easy_setopt(curl, CURLOPT_HTTPPOST, formpost); slist = curl_slist_append(slist, "Expect:"); curl_easy_setopt(curl, CURLOPT_HTTPHEADER, slist); - switch (session->host) { - case HOST_TWITTER: - curl_easy_setopt(curl, CURLOPT_URL, - twitter_update_url); - break; - case HOST_IDENTICA: - curl_easy_setopt(curl, CURLOPT_URL, - identica_update_url); - break; - } + + sprintf(endpoint, "%s%s", session->hosturl, update_uri); + curl_easy_setopt(curl, CURLOPT_URL, endpoint); curl_easy_setopt(curl, CURLOPT_USERPWD, user_password); break; case ACTION_FRIENDS: snprintf(user_password, sizeof(user_password), "%s:%s", session->account, session->password); - switch (session->host) { - case HOST_TWITTER: - sprintf(user_url, "%s?page=%d", twitter_friends_url, session->page); - curl_easy_setopt(curl, CURLOPT_URL, user_url); - break; - case HOST_IDENTICA: - sprintf(user_url, "%s?page=%d", identica_friends_url, session->page); - curl_easy_setopt(curl, CURLOPT_URL, user_url); - break; - } + sprintf(endpoint, "%s%s?page=%d", session->hosturl, + friends_uri, session->page); + curl_easy_setopt(curl, CURLOPT_URL, endpoint); curl_easy_setopt(curl, CURLOPT_USERPWD, user_password); break; case ACTION_USER: - switch (session->host) { - case HOST_TWITTER: - sprintf(user_url, "%s%s.xml?page=%d", twitter_user_url, session->user, session->page); - curl_easy_setopt(curl, CURLOPT_URL, user_url); - break; - case HOST_IDENTICA: - sprintf(user_url, "%s%s.xml?page=%d", identica_user_url, session->user, session->page); - curl_easy_setopt(curl, CURLOPT_URL, user_url); - break; - } + sprintf(endpoint, "%s%s%s.xml?page=%d", session->hosturl, user_uri, + session->user, session->page); + curl_easy_setopt(curl, CURLOPT_URL, endpoint); break; case ACTION_REPLIES: snprintf(user_password, sizeof(user_password), "%s:%s", session->account, session->password); - switch (session->host) { - case HOST_TWITTER: - sprintf(user_url, "%s?page=%d", twitter_replies_url, session->page); - curl_easy_setopt(curl, CURLOPT_URL, user_url); - break; - case HOST_IDENTICA: - sprintf(user_url, "%s?page=%d", identica_replies_url, session->page); - curl_easy_setopt(curl, CURLOPT_URL, user_url); - break; - } + sprintf(endpoint, "%s%s?page=%d", session->hosturl, replies_uri, session->page); + curl_easy_setopt(curl, CURLOPT_URL, endpoint); curl_easy_setopt(curl, CURLOPT_USERPWD, user_password); break; case ACTION_PUBLIC: - switch (session->host) { - case HOST_TWITTER: - sprintf(user_url, "%s?page=%d", twitter_public_url, session->page); - curl_easy_setopt(curl, CURLOPT_URL, user_url); - break; - case HOST_IDENTICA: - sprintf(user_url, "%s?page=%d", identica_public_url, session->page); - curl_easy_setopt(curl, CURLOPT_URL, user_url); - break; - } + sprintf(endpoint, "%s%s?page=%d", session->hosturl, public_uri, session->page); + curl_easy_setopt(curl, CURLOPT_URL, endpoint); break; default: @@ -521,6 +502,13 @@ static void parse_configfile(struct session *session) !strncasecmp(c, "yes", 3)) shrink_urls = 1; } + else if (!strncasecmp(c, "verbose", 7) && + (c[7] == '=')) { + c += 8; + if (!strncasecmp(c, "true", 4) || + !strncasecmp(c, "yes", 3)) + verbose = 1; + } } while (!feof(config_file)); if (password) @@ -528,10 +516,16 @@ static void parse_configfile(struct session *session) if (account) session->account = account; if (host) { - if (strcasecmp(host, "twitter") == 0) + if (strcasecmp(host, "twitter") == 0) { session->host = HOST_TWITTER; - if (strcasecmp(host, "identica") == 0) + session->hosturl = strdup(twitter_host); + } else if (strcasecmp(host, "identica") == 0) { session->host = HOST_IDENTICA; + session->hosturl = strdup(identica_host); + } else { + session->host = HOST_CUSTOM; + session->hosturl = strdup(host); + } free(host); } if (proxy) { @@ -591,7 +585,7 @@ static void log_session(struct session *session, int retval) host = "identi.ca"; break; default: - host = "unknown"; + host = session->hosturl; break; } @@ -909,6 +903,7 @@ int main(int argc, char *argv[], char *envp[]) { static const struct option options[] = { { "debug", 0, NULL, 'd' }, + { "verbose", 0, NULL, 'V' }, { "account", 1, NULL, 'a' }, { "password", 1, NULL, 'p' }, { "host", 1, NULL, 'H' }, @@ -934,6 +929,7 @@ int main(int argc, char *argv[], char *envp[]) int page_nr; debug = 0; + verbose = 0; rl_bind_key('\t', rl_insert); session = session_alloc(); @@ -964,7 +960,7 @@ int main(int argc, char *argv[], char *envp[]) parse_configfile(session); while (1) { - option = getopt_long_only(argc, argv, "dqe:p:P:H:a:A:u:hg:", + option = getopt_long_only(argc, argv, "dp:P:H:a:A:u:hg:snVv", options, NULL); if (option == -1) break; @@ -972,6 +968,9 @@ int main(int argc, char *argv[], char *envp[]) case 'd': debug = 1; break; + case 'V': + verbose = 1; + break; case 'a': if (session->account) free(session->account); @@ -1026,10 +1025,18 @@ int main(int argc, char *argv[], char *envp[]) session->shrink_urls = 1; break; case 'H': - if (strcasecmp(optarg, "twitter") == 0) + if (session->hosturl) + free(session->hosturl); + if (strcasecmp(optarg, "twitter") == 0) { session->host = HOST_TWITTER; - if (strcasecmp(optarg, "identica") == 0) + session->hosturl = strdup(twitter_host); + } else if (strcasecmp(optarg, "identica") == 0) { session->host = HOST_IDENTICA; + session->hosturl = strdup(identica_host); + } else { + session->host = HOST_CUSTOM; + session->hosturl = strdup(optarg); + } dbg("host = %d\n", session->host); break; case 'b': @@ -1050,6 +1057,13 @@ int main(int argc, char *argv[], char *envp[]) } } + /* + * Show the version to make it easier to determine what + * is going on here + */ + if (debug) + display_version(); + if (session->action == ACTION_UNKNOWN) { fprintf(stderr, "Unknown action, valid actions are:\n"); fprintf(stderr, "'update', 'friends', 'public', " @@ -1082,7 +1096,7 @@ int main(int argc, char *argv[], char *envp[]) session->tweet = zalloc(strlen(tweet) + 10); if (session->bash) - sprintf(session->tweet, "$ %s", tweet); + sprintf(session->tweet, "%c %s", getuid() ? '$' : '#', tweet); else sprintf(session->tweet, "%s", tweet);