From: Greg Kroah-Hartman Date: Mon, 19 May 2008 21:59:05 +0000 (-0700) Subject: initial commit of bti, everything's working now X-Git-Url: https://git.toastfreeware.priv.at/gregoa/bti.git/commitdiff_plain/6b6fec9dbb356936dd09b06bbe3ec1307f59f4ff?hp=badbca44ad46d0ecb114dad58419b3fd78e9f523 initial commit of bti, everything's working now --- diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..75ccb37 --- /dev/null +++ b/Makefile @@ -0,0 +1,112 @@ +# +# Copyright (C) 2006 Greg Kroah-Hartman +# +# 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 Free Software Foundation; version 2 of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# + +VERSION = 001 + +PROGRAM = bti + +CORE_OBJS = \ + bti.o + +GEN_HEADERS = \ + bti_version.h + +MAN_PAGES = \ + bti.1 + +CROSS_COMPILE ?= +CC = $(CROSS_COMPILE)gcc +LD = $(CROSS_COMPILE)gcc +AR = $(CROSS_COMPILE)ar + +override CFLAGS += -g -Wall -pipe -D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 -O2 + +WARNINGS = -Wstrict-prototypes -Wsign-compare -Wshadow \ + -Wchar-subscripts -Wmissing-declarations -Wnested-externs \ + -Wpointer-arith -Wcast-align -Wsign-compare -Wmissing-prototypes +CFLAGS += $(WARNINGS) +LDFLAGS += -Wl,-warn-common,--as-needed + + +ifeq ($(strip $(V)),) + E = @echo + Q = @ +else + E = @\# + Q = +endif +export E Q + + +# We need -lcurl for the curl stuff +# We need -lsocket and -lnsl when on Solaris +# We need -lssl and -lcrypto when using libcurl with SSL support +# We need -lpthread for the pthread example +#LIB_OBJS = -lcurl -lnsl -lssl -lcrypto +LIB_OBJS = -lcurl -lnsl + +all: $(PROGRAM) $(MAN_PAGES) + +# "Static Pattern Rule" to build all programs +bti: %: $(HEADERS) $(GEN_HEADERS) $(CORE_OBJS) + $(E) " LD " $@ + $(Q) $(LD) $(LDFLAGS) $(CORE_OBJS) -o $@ $(LIB_OBJS) + + +# build the objects +%.o: %.c $(HEADERS) $(GEN_HEADERS) + $(E) " CC " $@ + $(Q) $(CC) -c $(CFLAGS) $< -o $@ + + +bti_version.h: + $(E) " GENHDR " $@ + $(Q) echo "/* Generated by make. */" > $@ + $(Q) echo \#define BTI_VERSION \"$(VERSION)\" >> $@ + + +# man pages +%.1: %.xml + $(E) " XMLTO " $@ + $(Q) xmlto man $? +.PRECIOUS: %.3 + +clean: + $(E) " CLEAN " + $(Q) - find . -type f -name '*.orig' -print0 | xargs -0r rm -f + $(Q) - find . -type f -name '*.rej' -print0 | xargs -0r rm -f + $(Q) - find . -type f -name '*~' -print0 | xargs -0r rm -f + $(Q) - find . -type f -name '*.[oas]' -print0 | xargs -0r rm -f + $(Q) - find . -type f -name "*.gcno" -print0 | xargs -0r rm -f + $(Q) - find . -type f -name "*.gcda" -print0 | xargs -0r rm -f + $(Q) - find . -type f -name "*.gcov" -print0 | xargs -0r rm -f + $(Q) - rm -f core $(PROGRAM) $(GEN_HEADERS) +.PHONY: clean + +release: + $(Q) - rm -f bti-$(VERSION).tar.gz + $(Q) - rm -f bti-$(VERSION).tar.bz2 + head -1 ChangeLog | grep -q "to v$(VERSION)" + head -1 RELEASE-NOTES | grep -q "bti $(VERSION)" + git commit -a -m "release $(VERSION)" + cat .git/refs/heads/master > .git/refs/tags/$(VERSION) + @ echo + git-archive --format=tar --prefix=bti-$(VERSION)/ HEAD | gzip -9v > bti-$(VERSION).tar.gz + git-archive --format=tar --prefix=bti-$(VERSION)/ HEAD | bzip2 -9v > bti-$(VERSION).tar.bz2 +.PHONY: release + diff --git a/bti.1 b/bti.1 new file mode 100644 index 0000000..5e3b52a --- /dev/null +++ b/bti.1 @@ -0,0 +1,50 @@ +.\" Title: bti +.\" Author: +.\" Generator: DocBook XSL Stylesheets v1.73.2 +.\" Date: May 2008 +.\" Manual: bti +.\" Source: bti +.\" +.TH "BTI" "1" "May 2008" "bti" "bti" +.\" disable hyphenation +.nh +.\" disable justification (adjust text to left margin only) +.ad l +.SH "NAME" +bti - send a tweet to twitter.com from stdinput +.SH "SYNOPSIS" +.HP 4 +\fBbti\fR [\fB\-\-account\ account\fR] [\fB\-\-password\ password\fR] [\fB\-\-quiet\fR] [\fB\-\-debug\fR] [\fB\-\-version\fR] [\fB\-\-help\fR] +.SH "DESCRIPTION" +.PP +bti sends a twitter message to twitter\.com\. +.SH "OPTIONS" +.PP +\fB\-\-account account\fR +.RS 4 +Specify the twitter\.com account name\. +.RE +.PP +\fB\-\-password password\fR +.RS 4 +Specify the password of your twitter\.com account\. +.RE +.PP +\fB\-\-debug\fR +.RS 4 +Print a whole bunch of debugging messages to stdout\. +.RE +.PP +\fB\-\-version\fR +.RS 4 +Print version number\. +.RE +.PP +\fB\-\-help\fR +.RS 4 +Print help text\. +.RE +.SH "AUTHOR" +.PP +Written by Greg Kroah\-Hartman +\. diff --git a/bti.c b/bti.c new file mode 100644 index 0000000..11ba091 --- /dev/null +++ b/bti.c @@ -0,0 +1,377 @@ +/* + * Copyright (C) 2008 Greg Kroah-Hartman + * + * 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 + * Free Software Foundation version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "bti_version.h" + + +#define zalloc(size) calloc(size, 1) + +#define dbg(format, arg...) \ + do { \ + if (debug) \ + printf("%s: " format , __func__ , ## arg ); \ + } while (0) + + +static int debug = 0; + +struct session { + char *password; + char *account; + char *tweet; + int quiet; +}; + +struct bti_curl_buffer { + char *data; + int length; +}; + +static void display_help(void) +{ + fprintf(stdout, "bti - send tweet to twitter\n"); + fprintf(stdout, "Version: " BTI_VERSION "\n"); + fprintf(stdout, "Usage:\n"); + fprintf(stdout, " bti [options]\n"); + fprintf(stdout, "options are:\n"); + fprintf(stdout, " --account accountname\n"); + fprintf(stdout, " --password password\n"); + fprintf(stdout, " --bash\n"); + fprintf(stdout, " --quiet\n"); + fprintf(stdout, " --debug\n"); + fprintf(stdout, " --help\n"); +} + +static char *get_string_from_stdin(void) +{ + char *temp; + char *string; + + string = zalloc(100); + if (!string) + return NULL; + + if (!fgets(string, 99, stdin)) + return NULL; + temp = strchr(string, '\n'); + *temp = '\0'; + return string; +} + +static struct session *session_alloc(void) +{ + struct session *session; + + session = zalloc(sizeof(*session)); + if (!session) + return NULL; + return session; +} + +static void session_free(struct session *session) +{ + if (!session) + return; + free(session->password); + free(session->account); + free(session->tweet); + free(session); +} + +static struct bti_curl_buffer *bti_curl_buffer_alloc(void) +{ + struct bti_curl_buffer *buffer; + + buffer = zalloc(sizeof(*buffer)); + if (!buffer) + return NULL; + + /* start out with a data buffer of 1 byte to + * make the buffer fill logic simpler */ + buffer->data = zalloc(1); + if (!buffer->data) { + free(buffer); + return NULL; + } + buffer->length = 0; + return buffer; +} + +static void bti_curl_buffer_free(struct bti_curl_buffer *buffer) +{ + if (!buffer) + return; + free(buffer->data); + free(buffer); +} + +static const char *twitter_url = "https://twitter.com/statuses/update.xml"; + +static CURL *curl_init(void) +{ + CURL *curl; + + curl = curl_easy_init(); + if (!curl) { + fprintf(stderr, "Can not init CURL!\n"); + return NULL; + } + /* some ssl sanity checks on the connection we are making */ + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0); + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0); + return curl; +} + +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; + char *temp; + + if ((!buffer) || (!buffer_size) || (!curl_buf)) + return -EINVAL; + + /* add to the data we already have */ + temp = zalloc(curl_buf->length + buffer_size + 1); + if (!temp) + return -ENOMEM; + + memcpy(temp, curl_buf->data, curl_buf->length); + free(curl_buf->data); + curl_buf->data = temp; + memcpy(&curl_buf->data[curl_buf->length], (char *)buffer, buffer_size); + curl_buf->length += buffer_size; + + dbg("%s\n", curl_buf->data); + + return buffer_size; +} + +static int send_tweet(struct session *session) +{ + char user_password[500]; + char data[500]; + struct bti_curl_buffer *curl_buf; + CURL *curl = NULL; + CURLcode res; + struct curl_httppost *formpost = NULL; + struct curl_httppost *lastptr = NULL; + + if (!session) + return -EINVAL; + + curl_buf = bti_curl_buffer_alloc(); + if (!curl_buf) + return -ENOMEM; + + snprintf(user_password, sizeof(user_password), "%s:%s", + session->account, session->password); + snprintf(data, sizeof(data), "status=\"%s\"", session->tweet); + + curl = curl_init(); + if (!curl) + return -EINVAL; + + curl_formadd(&formpost, &lastptr, + CURLFORM_COPYNAME, "status", + CURLFORM_COPYCONTENTS, session->tweet, + CURLFORM_END); + + curl_easy_setopt(curl, CURLOPT_HTTPPOST, formpost); + curl_easy_setopt(curl, CURLOPT_URL, twitter_url); + if (debug) + curl_easy_setopt(curl, CURLOPT_VERBOSE, 1); + curl_easy_setopt(curl, CURLOPT_USERPWD, user_password); + + dbg("user_password = %s\n", user_password); + dbg("data = %s\n", data); + + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, curl_callback); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, curl_buf); + res = curl_easy_perform(curl); + if (res) { + printf("error(%d) trying to send tweet\n", res); + return -EINVAL; + } + + curl_easy_cleanup(curl); + curl_formfree(formpost); + bti_curl_buffer_free(curl_buf); + return 0; +} + +static void parse_configfile(struct session *session) +{ + FILE *config_file; + char *line = NULL; + size_t len = 0; + char *account = NULL; + char *password = NULL; + char *file; + char *home = getenv("HOME"); + + /* config file is ~/.bti */ + file = alloca(strlen(home) + 7); + + sprintf(file, "%s/.bti", home); + + config_file = fopen(file, "r"); + + /* No error if file does not exist or is unreadable. */ + if (config_file == NULL) + return; + + do { + ssize_t n = getline(&line, &len, config_file); + if (n < 0) + break; + if (line[n - 1] == '\n') + line[n - 1] = '\0'; + /* Parse file. Format is the usual value pairs: + account=name + passwort=value + # is a comment character + */ + *strchrnul(line, '#') = '\0'; + char *c = line; + while (isspace(*c)) + c++; + /* Ignore blank lines. */ + if (c[0] == '\0') + continue; + + if (!strncasecmp(c, "account", 7) && (c[7] == '=')) { + c += 8; + if (c[0] != '\0') + account = strdup(c); + } else if (!strncasecmp(c, "password", 8) && + (c[8] == '=')) { + c += 9; + if (c[0] != '\0') + password = strdup(c); + } + } while (!feof(config_file)); + + if (password) + session->password = password; + if (account) + session->account= account; + + /* Free buffer and close file. */ + free(line); + fclose(config_file); +} + +int main(int argc, char *argv[], char *envp[]) +{ + static const struct option options[] = { + { "debug", 0, NULL, 'd' }, + { "account", 1, NULL, 'a' }, + { "password", 1, NULL, 'p' }, + { "bash", 1, NULL, 'b' }, + { "help", 0, NULL, 'h' }, + { "quiet", 0, NULL, 'q' }, + { } + }; + struct session *session; + int retval; + int option; + + session = session_alloc(); + if (!session) { + fprintf(stderr, "no more memory...\n"); + return -1; + } + + curl_global_init(CURL_GLOBAL_ALL); + parse_configfile(session); + + while (1) { + option = getopt_long_only(argc, argv, "dqe:p:a:h", + options, NULL); + if (option == -1) + break; + switch (option) { + case 'd': + debug = 1; + break; + case 'a': + if (session->account) + free(session->account); + session->account = strdup(optarg); + dbg("account = %s\n", session->account); + break; + case 'p': + if (session->password) + free(session->password); + session->password = strdup(optarg); + dbg("password = %s\n", session->password); + break; + case 'q': + session->quiet = 1; + break; + case 'h': + display_help(); + goto exit; + default: + display_help(); + goto exit; + } + } + + if (!session->account) { + fprintf(stdout, "Enter twitter account: "); + session->account = get_string_from_stdin(); + } + + if (!session->password) { + fprintf(stdout, "Enter twitter password: "); + session->password = get_string_from_stdin(); + } + + session->tweet = get_string_from_stdin(); + + if (strlen(session->tweet) == 0) { + dbg("no tweet?\n"); + return -1; + } + + dbg("account = %s\n", session->account); + dbg("password = %s\n", session->password); + dbg("tweet = %s\n", session->tweet); + + retval = send_tweet(session); + if (retval) { + fprintf(stderr, "tweet failed\n"); + return -1; + } + + session_free(session); +exit: + return 0; +} diff --git a/bti.xml b/bti.xml new file mode 100644 index 0000000..cbda742 --- /dev/null +++ b/bti.xml @@ -0,0 +1,87 @@ + + + +
+
+ bti + + + bti + May 2008 + bti + + + + bti + 1 + + + + + btisend a tweet to twitter.com from stdinput + + + + + bti + + + + + + + + + + DESCRIPTION + bti sends a twitter message to twitter.com. + + + + OPTIONS + + + + + + Specify the twitter.com account name. + + + + + + + + Specify the password of your twitter.com account. + + + + + + + Print a whole bunch of debugging messages to stdout. + + + + + + Print version number. + + + + + + Print help text. + + + + + + AUTHOR + Written by Greg Kroah-Hartman greg@kroah.com. + + + +
+