2 * This program is free software; you can redistribute it and/or
3 * modify it under the terms of the GNU General Public License as
4 * published by the Free Software Foundation; either version 2 of the
5 * License, or (at your option) any later version.
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
10 * General Public License for more details.
12 * You should have received a copy of the GNU General Public
13 * License along with this program; if not, write to the
14 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
15 * Boston, MA 02110-1301 USA
17 * Authors: Travis Reitter <treitter@gmail.com>
23 #include <glib/gi18n.h>
25 #include <hildon/hildon.h>
27 #include <rtm-glib/rtm-error.h>
28 #include <rtm-glib/rtm-glib.h>
30 #include "milk-auth.h"
31 #include "milk-dialogs.h"
33 G_DEFINE_TYPE (MilkAuth, milk_auth, G_TYPE_OBJECT);
35 /* less expensive than G_TYPE_INSTANCE_GET_PRIVATE */
36 #define MILK_AUTH_PRIVATE(o) ((MILK_AUTH ((o)))->priv)
38 #define RTM_API_KEY "81f5c6c904aeafbbc914d9845d250ea8"
39 #define RTM_SHARED_SECRET "b08b15419378f913"
41 struct _MilkAuthPrivate
56 static MilkAuth *default_auth = NULL;
60 milk_auth_get_state (MilkAuth *auth)
62 g_return_val_if_fail (auth, MILK_AUTH_STATE_DISCONNECTED);
63 g_return_val_if_fail (MILK_IS_AUTH (auth),
64 MILK_AUTH_STATE_DISCONNECTED);
66 return MILK_AUTH_PRIVATE (auth)->state;
70 milk_auth_get_property (GObject *object,
75 MilkAuthPrivate *priv = MILK_AUTH_PRIVATE (object);
80 g_value_set_string (value, priv->api_key);
83 case PROP_SHARED_SECRET:
84 g_value_set_string (value, priv->shared_secret);
88 g_value_set_int (value, priv->state);
92 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id,
98 milk_auth_set_property (GObject *object,
103 MilkAuthPrivate *priv;
106 auth = MILK_AUTH (object);
107 priv = MILK_AUTH_PRIVATE (auth);
112 priv->api_key = g_value_dup_string (value);
115 case PROP_SHARED_SECRET:
116 priv->shared_secret = g_value_dup_string (value);
120 priv->state = g_value_get_int (value);
124 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id,
130 auth_response_cb (GtkWidget *dialog,
135 MilkAuthPrivate *priv;
136 GError *error = NULL;
139 MilkAuthState previous_state;
141 priv = MILK_AUTH_PRIVATE (auth);
143 previous_state = priv->state;
144 auth_token = rtm_glib_auth_get_token (priv->rtm_glib, priv->frob,
147 g_warning ("%s", rtm_error_get_message (error));
148 goto auth_response_cb_error_OUT;
151 if (!rtm_glib_auth_check_token (priv->rtm_glib, auth_token, NULL)) {
152 g_warning ("auth_token not valid!\n");
153 goto auth_response_cb_error_OUT;
156 g_warning ("%s", rtm_error_get_message (error));
157 goto auth_response_cb_error_OUT;
159 username = rtm_glib_test_login (priv->rtm_glib, auth_token, &error);
164 g_warning ("%s", rtm_error_get_message (error));
165 goto auth_response_cb_error_OUT;
168 priv->state = MILK_AUTH_STATE_CONNECTED;
169 goto auth_response_cb_OUT;
171 auth_response_cb_error_OUT:
172 priv->state = MILK_AUTH_STATE_DISCONNECTED;
173 /* FIXME: make it possible to re-try, etc. */
176 auth_response_cb_OUT:
177 if (priv->state != previous_state)
178 g_object_notify (G_OBJECT (auth), "state");
180 gtk_widget_destroy (dialog);
184 milk_auth_get_tasks (MilkAuth *auth,
185 const char *last_sync,
188 MilkAuthPrivate *priv;
191 g_return_val_if_fail (auth, NULL);
192 g_return_val_if_fail (MILK_IS_AUTH (auth), NULL);
193 g_return_val_if_fail (
194 milk_auth_get_state (auth) == MILK_AUTH_STATE_CONNECTED,
197 priv = MILK_AUTH_PRIVATE (auth);
199 /* FIXME: cache this */
200 rtm_tasks = rtm_glib_tasks_get_list (priv->rtm_glib, NULL, NULL,
201 (char*) last_sync, error);
207 milk_auth_timeline_create (MilkAuth *auth,
210 MilkAuthPrivate *priv;
212 g_return_val_if_fail (MILK_IS_AUTH (auth), NULL);
214 priv = MILK_AUTH_PRIVATE (auth);
216 return rtm_glib_timelines_create (priv->rtm_glib, error);
219 /* FIXME: we probably really want this to be async (but sequencable) */
221 milk_auth_tasks_add (MilkAuth *auth,
225 gboolean success = TRUE;
226 MilkAuthPrivate *priv;
229 GError *error = NULL;
231 g_return_val_if_fail (MILK_IS_AUTH (auth), NULL);
232 g_return_val_if_fail (names, NULL);
234 priv = MILK_AUTH_PRIVATE (auth);
236 for (l = names; l; l = l->next) {
239 /* FIXME: cut this */
240 g_debug ("trying to send task with name '%s'", l->data);
242 /* XXX: this uses Smart Add parsing; make this user-settable? */
243 /* XXX: the cast to char* is actually a bug in the rtm-glib API
245 task = rtm_glib_tasks_add (priv->rtm_glib, timeline,
246 l->data, NULL, TRUE, &error);
248 /* FIXME: cut this */
249 g_debug (G_STRLOC ": added task with ID '%s'",
250 rtm_task_get_id (task));
252 tasks = g_list_prepend (tasks, task);
254 g_warning ("failed to add some tasks: %s",
256 g_clear_error (&error);
264 milk_auth_task_add (MilkAuth *auth,
269 MilkAuthPrivate *priv;
271 g_return_val_if_fail (MILK_IS_AUTH (auth), NULL);
273 priv = MILK_AUTH_PRIVATE (auth);
275 /* XXX: this uses Smart Add parsing; make this user-settable? */
276 /* XXX: the cast to char* is actually a bug in the rtm-glib API */
277 return rtm_glib_tasks_add (priv->rtm_glib, timeline, (char*) name, NULL,
281 /* FIXME: we probably really want this to be async (but sequencable) */
283 milk_auth_tasks_send_changes (MilkAuth *auth,
287 gboolean success = TRUE;
288 MilkAuthPrivate *priv;
290 GList *tasks_sent = NULL;
291 GError *error = NULL;
293 g_return_val_if_fail (MILK_IS_AUTH (auth), NULL);
294 g_return_val_if_fail (tasks, NULL);
296 priv = MILK_AUTH_PRIVATE (auth);
298 for (l = tasks; l; l = l->next) {
299 RtmTask *task = l->data;
303 /* If any of these conditions fail, libsoup ends up exploding
304 * in a segfault (blindly de-reffing NULL); better to be safe
306 if (!rtm_task_get_list_id (task)) {
307 g_warning (G_STRLOC ": task doesn't have a list ID; "
312 if (!rtm_task_get_taskseries_id (task)) {
313 g_warning (G_STRLOC ": task doesn't have a taskseries "
318 if (!rtm_task_get_id (task)) {
319 g_warning (G_STRLOC ": task doesn't have an ID; "
324 tv = rtm_task_get_due_date (task);
329 due_str = g_time_val_to_iso8601 (tv);
331 /* FIXME: cut this */
332 g_debug ("going to set due string: '%s'", due_str);
334 /* XXX: this uses Smart Add parsing; make this
336 /* XXX: the cast to char* is actually a bug in the
338 tid = rtm_glib_tasks_set_due_date (priv->rtm_glib, timeline,
340 /* FIXME: set this appropriately */
345 /* FIXME: this should be a set, not a list --
346 * we'll add each task to the set if it's been
347 * changed since the last send */
348 tasks_sent = g_list_prepend (tasks_sent, task);
350 g_warning ("failed to add some tasks: %s",
352 g_clear_error (&error);
358 /* FIXME: handle all the other attributes, not just the date */
365 milk_auth_task_complete (MilkAuth *auth,
370 MilkAuthPrivate *priv;
372 g_return_val_if_fail (MILK_IS_AUTH (auth), NULL);
374 priv = MILK_AUTH_PRIVATE (auth);
376 return rtm_glib_tasks_complete (priv->rtm_glib, timeline, task, error);
380 milk_auth_task_delete (MilkAuth *auth,
385 MilkAuthPrivate *priv;
387 g_return_val_if_fail (MILK_IS_AUTH (auth), NULL);
389 priv = MILK_AUTH_PRIVATE (auth);
391 return rtm_glib_tasks_delete (priv->rtm_glib, timeline, task, error);
395 milk_auth_task_set_priority (MilkAuth *auth,
398 const char *priority,
401 MilkAuthPrivate *priv;
403 g_return_val_if_fail (MILK_IS_AUTH (auth), NULL);
405 priv = MILK_AUTH_PRIVATE (auth);
407 /* XXX: requiring a non-const gchar* priority is a bug in the rtm-glib
409 return rtm_glib_tasks_set_priority (priv->rtm_glib, timeline, task,
410 (gchar*) priority, error);
413 /* FIXME: why does this (or something above it) totally fail if we don't have a
414 * working Internet connection / resolv.conf is mangled? */
415 /* FIXME: instead of this manual call, listen to the connection manager
416 * transitions -- see this:
417 * http://wiki.maemo.org/Documentation/Maemo_5_Developer_Guide/Using_Connectivity_Components/Maemo_Connectivity#Libconic_Usage
420 milk_auth_log_in (MilkAuth *auth)
422 MilkAuthPrivate *priv;
423 GError *error = NULL;
427 g_return_if_fail (auth);
428 g_return_if_fail (MILK_IS_AUTH (auth));
430 priv = MILK_AUTH_PRIVATE (auth);
432 if (rtm_glib_test_echo (priv->rtm_glib, &error)) {
433 g_print ("Test echo OK!\n");
435 g_print ("Test echo FAIL!\n");
439 g_error ("%s", rtm_error_get_message (error));
443 /* FIXME: relocate this */
447 priv->frob = rtm_glib_auth_get_frob (priv->rtm_glib, &error);
449 g_error ("%s", rtm_error_get_message (error));
452 g_print ("Frob: %s\n", priv->frob);
454 url = rtm_glib_auth_get_login_url (priv->rtm_glib, priv->frob,
456 g_print ("URL: %s\n", url);
458 dialog = milk_dialogs_auth_prompt (NULL, url);
460 g_signal_connect (dialog, "response", G_CALLBACK (auth_response_cb),
465 milk_auth_constructed (GObject *object)
467 MilkAuthPrivate *priv = MILK_AUTH_PRIVATE (object);
469 priv->rtm_glib = rtm_glib_new (priv->api_key, priv->shared_secret);
473 milk_auth_finalize (GObject *object)
475 MilkAuthPrivate *priv = MILK_AUTH_PRIVATE (object);
477 g_object_unref (priv->rtm_glib);
479 g_free (priv->api_key);
480 g_free (priv->shared_secret);
485 milk_auth_class_init (MilkAuthClass *klass)
487 GObjectClass *object_class = G_OBJECT_CLASS (klass);
489 g_type_class_add_private (klass, sizeof (MilkAuthPrivate));
491 object_class->get_property = milk_auth_get_property;
492 object_class->set_property = milk_auth_set_property;
493 object_class->constructed = milk_auth_constructed;
494 object_class->finalize = milk_auth_finalize;
496 /* FIXME: make these read-only */
497 g_object_class_install_property
502 "API authentication key",
503 "Milk's API authentication key.",
505 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
506 G_PARAM_STATIC_STRINGS));
508 g_object_class_install_property
514 "Milk's shared secret with the server.",
516 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
517 G_PARAM_STATIC_STRINGS));
519 g_object_class_install_property
524 "Authentication state",
525 "Authentication/connection state with the server.",
526 0, (NUM_MILK_AUTH_STATES-1),
527 MILK_AUTH_STATE_DISCONNECTED,
528 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
529 G_PARAM_STATIC_STRINGS));
533 milk_auth_init (MilkAuth *self)
535 MilkAuthPrivate *priv;
537 self->priv = priv = G_TYPE_INSTANCE_GET_PRIVATE (
538 self, MILK_TYPE_AUTH, MilkAuthPrivate);
542 milk_auth_get_default ()
545 default_auth = g_object_new (MILK_TYPE_AUTH, NULL);