diff -rup --unidirectional-new-file raeddit-05/debian/control raeddit-06/debian/control --- raeddit-05/debian/control 2009-09-09 19:22:07.000000000 -0400 +++ raeddit-06/debian/control 2009-09-12 21:01:44.000000000 -0400 @@ -8,6 +8,7 @@ Standards-Version: 4 Package: raeddit Architecture: any Depends: ${shlibs:Depends}, ${misc:Depends} +Suggests: microfeed Description: View what's new online A simple front end to the social bookmarking site Reddit. XB-Maemo-Icon-26: diff -rup --unidirectional-new-file raeddit-05/debian/changelog raeddit-06/debian/changelog --- raeddit-05/debian/changelog 2009-09-10 13:03:49.000000000 -0400 +++ raeddit-06/debian/changelog 2009-09-12 21:02:30.000000000 -0400 @@ -1,3 +1,9 @@ +raeddit (0.60-1) unstable; urgency=low + + * Added sharing menu. + + -- Thomas Thurman Thu, 12 Sep 2009 21:02:22 -0400 + raeddit (0.50-1) unstable; urgency=low * Added menu when user selects a link diff -rup --unidirectional-new-file raeddit-05/Makefile raeddit-06/Makefile --- raeddit-05/Makefile 2009-09-09 23:22:15.000000000 -0400 +++ raeddit-06/Makefile 2009-09-12 20:48:18.000000000 -0400 @@ -1,7 +1,7 @@ all: raeddit -raeddit: raeddit.c greddit2.c - gcc `pkg-config --cflags --libs glib-2.0 hildon-1 json-glib-1.0 libcurl dbus-glib-1 gthread-2.0` raeddit.c greddit2.c -o raeddit +raeddit: raeddit.c greddit2.c sharing.c + gcc -g `pkg-config --cflags --libs glib-2.0 hildon-1 json-glib-1.0 libcurl dbus-glib-1 gthread-2.0` raeddit.c greddit2.c sharing.c -o raeddit install: raeddit raeddit.png raeddit.desktop install -d ${DESTDIR}/usr/bin diff -rup --unidirectional-new-file raeddit-05/raeddit.c raeddit-06/raeddit.c --- raeddit-05/raeddit.c 2009-09-09 23:35:35.000000000 -0400 +++ raeddit-06/raeddit.c 2009-09-12 20:23:18.000000000 -0400 @@ -113,6 +113,22 @@ read_comments_cb (GRedditPost *post, gbo } } +static gchar* +share_cb (GRedditPost *post, gboolean prepare) +{ + if (prepare) + { + return g_strdup_printf ("Share"); + } + else + { + sharing_choice (window, + post->url, + post->title); + return NULL; + } +} + typedef gchar* (*OptionCallback) (GRedditPost *, gboolean); static void @@ -122,6 +138,7 @@ options_selector (GtkButton *dummy, OptionCallback callbacks[] = { visit_site_cb, read_comments_cb, + share_cb, NULL }; OptionCallback *oc_cursor; diff -rup --unidirectional-new-file raeddit-05/sharing.c raeddit-06/sharing.c --- raeddit-05/sharing.c 1969-12-31 19:00:00.000000000 -0500 +++ raeddit-06/sharing.c 2009-09-12 21:01:00.000000000 -0400 @@ -0,0 +1,390 @@ +#include "sharing.h" +#include +#include +#include +#include +/* I love putting these two together */ +#include +#include + +/** + * \bug If these routines fail, they print debugging information to stderr, + * where it will rarely be seen. They should return it to the caller, + * or at least put up a dialogue. Yes, we're cutting a few corners here. + */ + +/** + * Keeps all the information in one place about what we want to send. + */ +typedef struct { + /** + * The display name of the service we're sending to. + */ + gchar *service_name; + /** + * The internal name of the service we're sending to. + */ + gchar *service; + /** + * The link we're sending. + * Should be a valid URL. + */ + gchar *link; + /** + * The title of the link. + */ + gchar *title; +} SharingMessage; + +/** + * Starts sending an email. Any of the parameters can be an empty string, though + * none of them should be NULL. This function will just take us to a screen where + * people can edit this stuff and then send the email, or cancel it. + * + * \param to The recipient. + * \param cc More recipients. + * \param bcc Recipients, but the other recipients won't see their names + * \param subject What the email is about. + * \param body The text of the email. + * \param attachments Comma-delimited set of escaped file:// URLs for attachments. + * + * \return True iff we forwarded the message upstream correctly. This does not + * mean the email was correctly sent. + */ +static gboolean +sharing_send_email (gchar *to, + gchar *cc, + gchar *bcc, + gchar *subject, + gchar *body, + gchar *attachments) +{ + DBusGConnection *connection; + GError *error = NULL; + DBusGProxy *proxy; + + connection = dbus_g_bus_get (DBUS_BUS_SESSION, + &error); + if (connection == NULL) + { + fprintf (stderr, "ERROR: %s", error->message); + g_error_free (error); + return FALSE; + } + + proxy = dbus_g_proxy_new_for_name (connection, + "com.nokia.modest", + "/com/nokia/modest", + "com.nokia.modest"); + + error = NULL; + if (!dbus_g_proxy_call (proxy, "ComposeMail", &error, + G_TYPE_STRING, to, + G_TYPE_STRING, cc, + G_TYPE_STRING, bcc, + G_TYPE_STRING, subject, + G_TYPE_STRING, body, + G_TYPE_STRING, attachments, + G_TYPE_INVALID, + G_TYPE_INVALID)) + { + fprintf (stderr, "ERROR: %s\n", error->message); + g_error_free (error); + return FALSE; + } + + return TRUE; +} + +/** + * Posts a message on twitter, identica, jaiku, etc. + * + * \param publisher The publisher, e.g. "Identica" for identi.ca. + * \param provider The providing class, e.g. + * "org.microfeed.Provider.Twitter" for identi.ca + * (because it uses the same backend as Twitter). + * \param message What you actually wanted to say. It would be + * sensible to keep this below 140 characters, but + * it will still work if you don't (Twitter will + * show the tweet in full if you look at it; it'll + * just appear truncated in people's feeds). + * + * \return true iff there was no problem communicating the + * message upstream. As explained below, this doesn't + * mean that the message was posted, unfortunately. + * + * \bug Currently doesn't check for the signal to say that + * the posting *failed*. There is AFAIK no way in libmicrofeed + * to know that the posting succeeded other than to wait + * an indefinite time and not get a failure signal. + * + * \bug May print debugging output to stderr if things go wrong + * in sending. + */ +static gboolean +sharing_send_tweet (gchar *publisher, + gchar *provider, + gchar *message) +{ + DBusGConnection *connection; + GError *error = NULL; + gchar *str; + DBusGProxy *proxy; + + connection = dbus_g_bus_get (DBUS_BUS_SESSION, + &error); + if (connection == NULL) + { + fprintf (stderr, "ERROR: %s", error->message); + g_error_free (error); + return FALSE; + } + + str = g_strdup_printf ("/org/microfeed/publisher/%s", + publisher); + proxy = dbus_g_proxy_new_for_name (connection, + "org.microfeed.Provider.Twitter", + str, + "org.microfeed.Publisher"); + g_free (str); + + /* get some unique code for this tweet, which isn't important + * anyway at the moment because we're being fire-and-forget, + * so we'll never + * but let's make the code unique on principle + */ + str = g_strdup_printf ("%d.%d.%ld", + getpid (), + time (NULL), + random ()); + error = NULL; + if (!dbus_g_proxy_call (proxy, "AddItem", &error, + /* Why ":Overview"? The specs seem + * to say it should be a URL-like string: + * "http://microfeed.org/Feed/Overview". + * But that doesn't do anything. + * But this is what Mauku does, so + * we'll do that. + */ + G_TYPE_STRING, ":Overview", + + /* Some unique ID */ + G_TYPE_STRING, str, + + /* This uses the *old* method of + * identifying a client, which + * isn't open to new registrations. + * Therefore we will pretend to + * be blt, which was registered before + * the rules changed. + */ + G_TYPE_STRING, ".twitter.source", + G_TYPE_STRING, "blt", + + /* And now, what we actually wanted to say. */ + G_TYPE_STRING, "content.text", + G_TYPE_STRING, message, + + G_TYPE_INVALID, + G_TYPE_INVALID)) + { + fprintf (stderr, "ERROR: %s\n", error->message); + g_error_free (error); + g_free (str); + return FALSE; + } + + g_free (str); + return TRUE; +} + +/** + * Scans one directory for microfeed providers. + * Helper function for sharing_scan_for_microfeeds(). + * + * \param dir_name Name of the directory to scan. + * \param options Hash table to stick the results into. + */ +static void +sharing_scan_directory_for_microfeeds (const gchar *dir_name, + GHashTable *options) +{ + glob_t globbuf; + gchar *target = g_strdup_printf ("%s/*-*", dir_name); + GRegex *re = g_regex_new ("/([^/-]*)-(.*)$", + 0, 0, NULL); + GMatchInfo *found = NULL; + gint i; + + glob (target, 0, NULL, &globbuf); + + for (i=0; iservice, EMAIL_KEY)==0) + { + /* Special case for email */ + sharing_send_email ("", /* no "to", "cc", or "bcc" */ + "", + "", + message->title, + message->link, + ""); /* no attachments */ + } + else + { + /* One day, we might want to call some sort of + * URL shortening service here. + */ + + gchar *str = g_strdup_printf ("%s %s (via raeddit)", + message->link, + message->title); + + sharing_send_tweet (message->service_name, + message->service, + str); + + g_free (str); + } + + g_free (message->service_name); + g_free (message->service); + g_free (message->title); + g_free (message->link); + g_free (message); +} + +void +sharing_choice (GtkWindow *window, + char *link, + char *title) +{ + GtkWidget *dialog; + GtkWidget *selector; + /** + * A map of strings which are display names to strings which are names of + * microfeed providers. EMAIL_KEY is a special case that sends email + * instead. A more elegant solution would be to map to (function pointer, + * arbitrary data pointer) pairs; if we add any more special cases we + * should do this. + */ + GHashTable *options = g_hash_table_new_full (g_str_hash, g_str_equal, + g_free, + g_free); + GList *options_list, *cursor; + SharingMessage *message = g_new (SharingMessage, 1); + + message->link = g_strdup (link); + message->title = g_strdup (title); + + dialog = hildon_picker_dialog_new (GTK_WINDOW (window)); + selector = hildon_touch_selector_new_text (); + gtk_window_set_title (GTK_WINDOW (dialog), "How would you like to share it?"); + + /* You always have email available. */ + g_hash_table_insert (options, g_strdup (EMAIL_KEY), g_strdup (EMAIL_KEY)); + + /* And let's see what microfeeds we know about. */ + sharing_scan_for_microfeeds (options); + + options_list = g_hash_table_get_keys (options); + for (cursor = options_list; cursor; cursor=cursor->next) + { + gchar *line = (gchar *) cursor->data; + + hildon_touch_selector_append_text (HILDON_TOUCH_SELECTOR (selector), + line); + } + g_list_free (options_list); + + hildon_picker_dialog_set_selector (HILDON_PICKER_DIALOG (dialog), + HILDON_TOUCH_SELECTOR (selector)); + + gtk_widget_show_all (GTK_WIDGET (GTK_DIALOG (dialog)->vbox)); + + if (gtk_dialog_run (GTK_DIALOG (dialog))!=GTK_RESPONSE_OK) + { + gtk_widget_destroy (GTK_WIDGET (dialog)); + g_hash_table_unref (options); + return; + } + + message->service_name = g_strdup + (hildon_touch_selector_get_current_text (HILDON_TOUCH_SELECTOR (selector))); + message->service = g_strdup ((gchar*) g_hash_table_lookup (options, + message->service_name)); + + if (!g_thread_create(&sharing_send_message_thread, message, FALSE, NULL) != 0) + { + /* oh dear. */ + fprintf (stderr, "Couldn't create the thread. Can't send the message.\n"); + } + + gtk_widget_destroy (GTK_WIDGET (dialog)); + g_hash_table_unref (options); + + return; +} + +/* eof sharing.c */ diff -rup --unidirectional-new-file raeddit-05/sharing.h raeddit-06/sharing.h --- raeddit-05/sharing.h 1969-12-31 19:00:00.000000000 -0500 +++ raeddit-06/sharing.h 2009-09-12 21:11:11.000000000 -0400 @@ -0,0 +1,40 @@ +/* + * Simple DBus routines to share links. + * Copyright (c) 2009 Thomas Thurman + * thomas@thurman.org.uk + * + * 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; either version 2 of the License, or + * (at your option) any later version. + * + * 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 be able to view the GNU General Public License at + * http://www.gnu.org/copyleft/gpl.html ; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef SHARING_H +#define SHARING_H 1 + +#include + +/** + * Puts up a selector to let the user choose how to share a link. + * + * \param window The parent for the selector. + * \param link The link. + * \param title The title of the link. + */ +void +sharing_choice (GtkWindow *window, + char *link, + char *title); + +#endif /* SHARING_H */ + +/* eof sharing.h */