2 * Copyright (C) 2008 Greg Kroah-Hartman <greg@kroah.com>
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License as published by the
6 * Free Software Foundation version 2 of the License.
8 * This program is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * General Public License for more details.
13 * You should have received a copy of the GNU General Public License along
14 * with this program; if not, write to the Free Software Foundation, Inc.,
15 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
28 #include <curl/curl.h>
29 #include "bti_version.h"
32 #define zalloc(size) calloc(size, 1)
34 #define dbg(format, arg...) \
37 printf("%s: " format , __func__ , ## arg ); \
50 struct bti_curl_buffer {
55 static void display_help(void)
57 fprintf(stdout, "bti - send tweet to twitter\n");
58 fprintf(stdout, "Version: " BTI_VERSION "\n");
59 fprintf(stdout, "Usage:\n");
60 fprintf(stdout, " bti [options]\n");
61 fprintf(stdout, "options are:\n");
62 fprintf(stdout, " --account accountname\n");
63 fprintf(stdout, " --password password\n");
64 fprintf(stdout, " --bash\n");
65 fprintf(stdout, " --quiet\n");
66 fprintf(stdout, " --debug\n");
67 fprintf(stdout, " --help\n");
70 static char *get_string_from_stdin(void)
79 if (!fgets(string, 99, stdin))
81 temp = strchr(string, '\n');
86 static struct session *session_alloc(void)
88 struct session *session;
90 session = zalloc(sizeof(*session));
96 static void session_free(struct session *session)
100 free(session->password);
101 free(session->account);
102 free(session->tweet);
106 static struct bti_curl_buffer *bti_curl_buffer_alloc(void)
108 struct bti_curl_buffer *buffer;
110 buffer = zalloc(sizeof(*buffer));
114 /* start out with a data buffer of 1 byte to
115 * make the buffer fill logic simpler */
116 buffer->data = zalloc(1);
125 static void bti_curl_buffer_free(struct bti_curl_buffer *buffer)
133 static const char *twitter_url = "https://twitter.com/statuses/update.xml";
135 static CURL *curl_init(void)
139 curl = curl_easy_init();
141 fprintf(stderr, "Can not init CURL!\n");
144 /* some ssl sanity checks on the connection we are making */
145 curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0);
146 curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0);
150 size_t curl_callback(void *buffer, size_t size, size_t nmemb, void *userp)
152 struct bti_curl_buffer *curl_buf = userp;
153 size_t buffer_size = size * nmemb;
156 if ((!buffer) || (!buffer_size) || (!curl_buf))
159 /* add to the data we already have */
160 temp = zalloc(curl_buf->length + buffer_size + 1);
164 memcpy(temp, curl_buf->data, curl_buf->length);
165 free(curl_buf->data);
166 curl_buf->data = temp;
167 memcpy(&curl_buf->data[curl_buf->length], (char *)buffer, buffer_size);
168 curl_buf->length += buffer_size;
170 dbg("%s\n", curl_buf->data);
175 static int send_tweet(struct session *session)
177 char user_password[500];
179 struct bti_curl_buffer *curl_buf;
182 struct curl_httppost *formpost = NULL;
183 struct curl_httppost *lastptr = NULL;
188 curl_buf = bti_curl_buffer_alloc();
192 snprintf(user_password, sizeof(user_password), "%s:%s",
193 session->account, session->password);
194 snprintf(data, sizeof(data), "status=\"%s\"", session->tweet);
200 curl_formadd(&formpost, &lastptr,
201 CURLFORM_COPYNAME, "status",
202 CURLFORM_COPYCONTENTS, session->tweet,
205 curl_easy_setopt(curl, CURLOPT_HTTPPOST, formpost);
206 curl_easy_setopt(curl, CURLOPT_URL, twitter_url);
208 curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);
209 curl_easy_setopt(curl, CURLOPT_USERPWD, user_password);
211 dbg("user_password = %s\n", user_password);
212 dbg("data = %s\n", data);
214 curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, curl_callback);
215 curl_easy_setopt(curl, CURLOPT_WRITEDATA, curl_buf);
216 res = curl_easy_perform(curl);
218 printf("error(%d) trying to send tweet\n", res);
222 curl_easy_cleanup(curl);
223 curl_formfree(formpost);
224 bti_curl_buffer_free(curl_buf);
228 static void parse_configfile(struct session *session)
233 char *account = NULL;
234 char *password = NULL;
236 char *home = getenv("HOME");
238 /* config file is ~/.bti */
239 file = alloca(strlen(home) + 7);
241 sprintf(file, "%s/.bti", home);
243 config_file = fopen(file, "r");
245 /* No error if file does not exist or is unreadable. */
246 if (config_file == NULL)
250 ssize_t n = getline(&line, &len, config_file);
253 if (line[n - 1] == '\n')
255 /* Parse file. Format is the usual value pairs:
258 # is a comment character
260 *strchrnul(line, '#') = '\0';
264 /* Ignore blank lines. */
268 if (!strncasecmp(c, "account", 7) && (c[7] == '=')) {
272 } else if (!strncasecmp(c, "password", 8) &&
276 password = strdup(c);
278 } while (!feof(config_file));
281 session->password = password;
283 session->account= account;
285 /* Free buffer and close file. */
290 int main(int argc, char *argv[], char *envp[])
292 static const struct option options[] = {
293 { "debug", 0, NULL, 'd' },
294 { "account", 1, NULL, 'a' },
295 { "password", 1, NULL, 'p' },
296 { "bash", 1, NULL, 'b' },
297 { "help", 0, NULL, 'h' },
298 { "quiet", 0, NULL, 'q' },
301 struct session *session;
307 session = session_alloc();
309 fprintf(stderr, "no more memory...\n");
313 curl_global_init(CURL_GLOBAL_ALL);
314 parse_configfile(session);
317 option = getopt_long_only(argc, argv, "dqe:p:a:h",
326 if (session->account)
327 free(session->account);
328 session->account = strdup(optarg);
329 dbg("account = %s\n", session->account);
332 if (session->password)
333 free(session->password);
334 session->password = strdup(optarg);
335 dbg("password = %s\n", session->password);
349 if (!session->account) {
350 fprintf(stdout, "Enter twitter account: ");
351 session->account = get_string_from_stdin();
354 if (!session->password) {
355 fprintf(stdout, "Enter twitter password: ");
356 session->password = get_string_from_stdin();
359 /* Add the "$ " to the start of the tweet to show it's coming from
361 tweet = get_string_from_stdin();
362 session->tweet = zalloc(strlen(tweet) + 10);
363 sprintf(session->tweet, "$ %s", tweet);
366 if (strlen(session->tweet) == 0) {
371 dbg("account = %s\n", session->account);
372 dbg("password = %s\n", session->password);
373 dbg("tweet = %s\n", session->tweet);
375 /* fork ourself so that the main shell can get on
376 * with it's life as we try to connect and handle everything
380 dbg("child is %d\n", child);
384 retval = send_tweet(session);
386 fprintf(stderr, "tweet failed\n");
390 session_free(session);