Add support for FeedingIt
[feedhandler] / feedhandler.vala
1 /**
2  * Feed Handler
3  * Copyright © 2009 Thomas Perl <thp@thpinfo.com>
4  **/
5
6 using Gtk;
7 using GLib;
8 using Osso;
9 using Pango;
10
11 public static const string FEEDINGIT_SERVICE =
12     "/usr/share/dbus-1/services/feedingit.service";
13
14 public enum Reader {
15     RSS = 1,
16     GOOGLE,
17     GPODDER,
18     FEEDINGIT,
19 }
20
21 public class DesktopFile : GLib.KeyFile {
22     public DesktopFile(string basename) {
23         string filename = "/usr/share/applications/" + basename.replace("hildon-", "hildon/");
24         try {
25             load_from_file(filename, KeyFileFlags.NONE);
26         } catch (KeyFileError e) {
27             stderr.printf("Cannot open key file: %s\n", e.message);
28         } catch (FileError e) {
29             stderr.printf("Cannot open key file: %s\n", e.message);
30         }
31     }
32
33     public string? get_name() {
34         try {
35             return get_string("Desktop Entry", "Name");
36         } catch (KeyFileError e) {
37             stderr.printf("Cannot read exec key: %s\n", e.message);
38         }
39         return null;
40     }
41
42     public string? get_executable() {
43         try {
44             return get_string("Desktop Entry", "Exec");
45         } catch (KeyFileError e) {
46             stderr.printf("Cannot read exec key: %s\n", e.message);
47         }
48         return null;
49     }
50 }
51
52 public class MimeCache : GLib.KeyFile {
53     public MimeCache(string filename="/usr/share/applications/mimeinfo.cache") {
54         try {
55             load_from_file(filename, KeyFileFlags.NONE);
56         } catch (KeyFileError e) {
57             stderr.printf("Cannot open key file: %s\n", e.message);
58         } catch (FileError e) {
59             stderr.printf("Cannot open key file: %s\n", e.message);
60         }
61     }
62
63     public string [] get_desktop_files(string mimetype="application/news_reader") {
64         try {
65             return get_string("MIME Cache", mimetype).split(";");
66         } catch (KeyFileError e) {
67             stderr.printf("Cannot get desktop files for %s\n", mimetype);
68             return new string [0];
69         }
70     }
71 }
72
73 [DBus (name="org.maemo.garage.feedhandler")]
74 public class FeedHandler : GLib.Object {
75     private MainLoop loop;
76     private DBus.Connection conn;
77     private Osso.Context context;
78     private string args_url;
79     private MimeCache mime_cache;
80
81     public FeedHandler(MainLoop loop, DBus.Connection conn) {
82         this.loop = loop;
83         this.conn = conn;
84         this.context = new Osso.Context("feedhandler", "2.0", false, null);
85         this.args_url = null;
86         this.mime_cache = new MimeCache();
87
88         foreach (string file in mime_cache.get_desktop_files("application/rss+xml")) {
89             if (file != "") {
90                 var desktop_file = new DesktopFile(file);
91                 var name = desktop_file.get_name();
92                 var exec = desktop_file.get_executable();
93                 if (name != null && exec != null) {
94                     stderr.printf("File in Mime CACHE: %s (%s)\n", name, exec);
95                     /* XXX: Add "Name" as option and on select, start exec + URL */
96                 }
97             }
98         }
99     }
100
101     [DBus (name = "mime_open")]
102     public void mime_open(string url) {
103         int result;
104
105         Gtk.Dialog dlg = new Gtk.Dialog();
106         dlg.add_button("RSS Reader", Reader.RSS);
107         dlg.add_button("Google Reader", Reader.GOOGLE);
108         if (FileUtils.test("/usr/bin/gpodder", FileTest.EXISTS)) {
109             dlg.add_button("gPodder", Reader.GPODDER);
110         }
111         if (FileUtils.test(FEEDINGIT_SERVICE, FileTest.EXISTS)) {
112             dlg.add_button("FeedingIt", Reader.FEEDINGIT);
113         }
114         dlg.add_button("Cancel", Gtk.ResponseType.CLOSE);
115         dlg.title = "Select application for handling this feed";
116         var label = new Gtk.Label(url);
117         label.ellipsize = Pango.EllipsizeMode.END;
118         dlg.vbox.add(label);
119         dlg.show_all();
120         result = dlg.run();
121         dlg.destroy();
122
123         switch (result) {
124             case Reader.RSS:
125                 add_to_rss_reader(url);
126                 break;
127             case Reader.GOOGLE:
128                 add_to_google(url);
129                 break;
130             case Reader.GPODDER:
131                 try {
132                     GLib.Process.spawn_async(null,
133                         {"gpodder",
134                         "--fremantle",
135                         "-s",
136                         url}, null, GLib.SpawnFlags.SEARCH_PATH, null, null);
137                 } catch (GLib.SpawnError e) {
138                     stderr.printf("Can't launch: %s\n", e.message);
139                 }
140                 break;
141             case Reader.FEEDINGIT:
142                 add_to_feedingit(url);
143                 break;
144         }
145
146         message("URL received: %s", url);
147         loop.quit();
148     }
149
150     private void add_to_google(string url)
151     {
152         open_browser("http://fusion.google.com/add?feedurl=" +
153             Uri.escape_string(url, "", false));
154     }
155
156     private void add_to_rss_reader(string url)
157     {
158         dynamic DBus.Object obj = conn.get_object(
159             "com.nokia.osso_rss_feed_reader_refresh",
160             "/com/nokia/osso_rss_feed_reader_refresh",
161             "com.nokia.osso_rss_feed_reader_refresh");
162         obj.mime_open(url);
163     }
164
165     private void add_to_feedingit(string url)
166     {
167         dynamic DBus.Object obj = conn.get_object(
168             "org.maemo.feedingit",
169             "/org/maemo/feedingit",
170             "org.maemo.feedingit");
171         obj.AddFeed(url);
172     }
173
174     private void open_browser(string url)
175     {
176         context.rpc_run_with_defaults("osso_browser",
177                                       "open_new_window",
178                                       null,
179                                       (int)'s', url,
180                                       (int)'\0');
181         /* DBUS_TYPE_STRING is (int)'s' */
182         /* DBUS_TYPE_INVALID is (int)'\0' */
183     }
184
185     public void set_args_url(string url)
186     {
187         args_url = url;
188     }
189
190     public bool open_url_later()
191     {
192         mime_open(args_url);
193         return false;
194     }
195 }
196
197 static int main(string [] args) {
198     MainLoop loop = new MainLoop(null, false);
199     Gtk.init(ref args);
200     if (args.length != 1 && args.length != 2) {
201         stderr.printf("Usage: %s [URL]\n", args[0]);
202         return 1;
203     }
204     try {
205         DBus.Connection conn = DBus.Bus.get(DBus.BusType.SESSION);
206         dynamic DBus.Object bus = conn.get_object("org.freedesktop.DBus",
207                                                   "/org/freedesktop/DBus",
208                                                   "org.freedesktop.DBus");
209         uint request_name_result = bus.RequestName(
210                                  "org.maemo.garage.feedhandler", (uint)0);
211         if (request_name_result == DBus.RequestNameReply.PRIMARY_OWNER) {
212             FeedHandler server = new FeedHandler(loop, conn);
213             conn.register_object("/org/maemo/garage/feedhandler", server);
214             if (args.length == 2) {
215                 /* Add URL when the main loop is running */
216                 server.set_args_url(args[1]);
217                 Idle.add(server.open_url_later);
218             }
219             loop.run();
220         } else {
221             stderr.printf("feedhandler is already running.\n");
222         }
223     }
224     catch (Error e) {
225         stderr.printf("OOps: %s\n", e.message);
226     }
227     return 0;
228 }
229