Add a basic task cache
[milk] / src / milk-auth.c
index 8f81131..c36db6a 100644 (file)
@@ -44,16 +44,28 @@ struct _MilkAuthPrivate
         char *api_key;
         char *shared_secret;
         char *frob;
+        MilkAuthState state;
 };
 
 enum {
         PROP_API_KEY = 1,
         PROP_SHARED_SECRET,
+        PROP_STATE,
 };
 
 static MilkAuth *default_auth = NULL;
 
 
+MilkAuthState
+milk_auth_get_state (MilkAuth *auth)
+{
+        g_return_val_if_fail (auth, MILK_AUTH_STATE_DISCONNECTED);
+        g_return_val_if_fail (MILK_IS_AUTH (auth),
+                        MILK_AUTH_STATE_DISCONNECTED);
+
+        return MILK_AUTH_PRIVATE (auth)->state;
+}
+
 static void
 milk_auth_get_property (GObject    *object,
                         guint       property_id,
@@ -72,6 +84,10 @@ milk_auth_get_property (GObject    *object,
                         g_value_set_string (value, priv->shared_secret);
                 break;
 
+                case PROP_STATE:
+                        g_value_set_int (value, priv->state);
+                break;
+
                 default:
                         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id,
                                         pspec);
@@ -100,6 +116,10 @@ milk_auth_set_property (GObject      *object,
                         priv->shared_secret = g_value_dup_string (value);
                 break;
 
+                case PROP_STATE:
+                        priv->state = g_value_get_int (value);
+                break;
+
                 default:
                         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id,
                                         pspec);
@@ -113,96 +133,281 @@ auth_response_cb (GtkWidget *dialog,
 
 {
         MilkAuthPrivate *priv;
-
         GError *error = NULL;
         gchar *auth_token;
         gchar *username;
+        MilkAuthState previous_state;
 
         priv = MILK_AUTH_PRIVATE (auth);
 
+        previous_state = priv->state;
         auth_token = rtm_glib_auth_get_token (priv->rtm_glib, priv->frob,
                         &error);
         if (error != NULL) {
-                g_error ("%s", rtm_error_get_message (error));
-                goto auth_response_cb_OUT;
+                g_warning ("%s", rtm_error_get_message (error));
+                goto auth_response_cb_error_OUT;
         }
 
         if (!rtm_glib_auth_check_token (priv->rtm_glib, auth_token, NULL)) {
-                g_error ("auth_token not valid!\n");
+                g_warning ("auth_token not valid!\n");
                 goto auth_response_cb_error_OUT;
         }
         if (error != NULL) {
-                g_error ("%s", rtm_error_get_message (error));
-                goto auth_response_cb_OUT;
+                g_warning ("%s", rtm_error_get_message (error));
+                goto auth_response_cb_error_OUT;
         }
         username = rtm_glib_test_login (priv->rtm_glib, auth_token, &error);
 
         g_free (auth_token);
 
         if (error != NULL) {
-                g_error ("%s", rtm_error_get_message (error));
-                goto auth_response_cb_OUT;
+                g_warning ("%s", rtm_error_get_message (error));
+                goto auth_response_cb_error_OUT;
         }
 
-        /* FIXME: work this in where appropriate */
-#if 0
-        glist = rtm_glib_tasks_get_list (priv->rtm_glib, NULL, NULL, NULL, &error);
-        if (error != NULL) {
-                g_error ("%s", rtm_error_get_message (error));
-        }
-        for (item = glist; item; item = g_list_next (item)) {
-                task = (RtmTask *) item->data;
-                g_print ("%s", rtm_task_to_string (task));
-        }
-        g_list_free (glist);
+        priv->state = MILK_AUTH_STATE_CONNECTED;
+        goto auth_response_cb_OUT;
 
-        glist = rtm_glib_lists_get_list (priv->rtm_glib, &error);
-        if (error != NULL) {
-                g_error ("%s", rtm_error_get_message (error));
-                goto auth_response_cb_OUT;
-        }
-        for (item = glist; item; item = g_list_next (item)) {
-                rtm_list = (RtmList *) item->data;
-                if (g_strcmp0 (rtm_list_get_name (rtm_list), "Sent") == 0) {
-                        list_id_sent = rtm_list_get_id (rtm_list);
+auth_response_cb_error_OUT:
+        priv->state = MILK_AUTH_STATE_DISCONNECTED;
+        /* FIXME: make it possible to re-try, etc. */
+        gtk_main_quit ();
+
+auth_response_cb_OUT:
+        if (priv->state != previous_state)
+                g_object_notify (G_OBJECT (auth), "state");
+
+        gtk_widget_destroy (dialog);
+}
+
+GList *
+milk_auth_get_tasks (MilkAuth    *auth,
+                     const char  *last_sync,
+                     GError     **error)
+{
+        MilkAuthPrivate *priv;
+        GList *rtm_tasks;
+
+        g_return_val_if_fail (auth, NULL);
+        g_return_val_if_fail (MILK_IS_AUTH (auth), NULL);
+        g_return_val_if_fail (
+                        milk_auth_get_state (auth) == MILK_AUTH_STATE_CONNECTED,
+                        NULL);
+
+        priv = MILK_AUTH_PRIVATE (auth);
+
+        /* FIXME: cache this */
+        rtm_tasks = rtm_glib_tasks_get_list (priv->rtm_glib, NULL, NULL,
+                        (char*) last_sync, error);
+
+        return rtm_tasks;
+}
+
+char*
+milk_auth_timeline_create (MilkAuth  *auth,
+                           GError   **error)
+{
+        MilkAuthPrivate *priv;
+
+        g_return_val_if_fail (MILK_IS_AUTH (auth), NULL);
+
+        priv = MILK_AUTH_PRIVATE (auth);
+
+        return rtm_glib_timelines_create (priv->rtm_glib, error);
+}
+
+/* FIXME: we probably really want this to be async (but sequencable) */
+GList*
+milk_auth_tasks_add (MilkAuth  *auth,
+                     char      *timeline,
+                     GList     *names)
+{
+        gboolean success = TRUE;
+        MilkAuthPrivate *priv;
+        GList *l;
+        GList *tasks = NULL;
+        GError *error = NULL;
+
+        g_return_val_if_fail (MILK_IS_AUTH (auth), NULL);
+        g_return_val_if_fail (names, NULL);
+
+        priv = MILK_AUTH_PRIVATE (auth);
+
+        for (l = names; l; l = l->next) {
+                RtmTask *task;
+
+                /* FIXME: cut this */
+                g_debug ("trying to send task with name '%s'", l->data);
+
+                /* XXX: this uses Smart Add parsing; make this user-settable? */
+                /* XXX: the cast to char* is actually a bug in the rtm-glib API
+                 */
+                task = rtm_glib_tasks_add (priv->rtm_glib, timeline,
+                                l->data, NULL, TRUE, &error);
+                if (task) {
+                        /* FIXME: cut this */
+                        g_debug (G_STRLOC ": added task with ID '%s'",
+                                        rtm_task_get_id (task));
+
+                        tasks = g_list_prepend (tasks, task);
+                } else {
+                        g_warning ("failed to add some tasks: %s",
+                                        error->message);
+                        g_clear_error (&error);
                 }
-                g_print ("%s", rtm_list_to_string (rtm_list));
         }
-        g_list_free (glist);
 
-        timeline = rtm_glib_timelines_create (priv->rtm_glib, &error);
-        if (error != NULL) {
-                g_error ("%s", rtm_error_get_message (error));
-        }
-        g_print ("timeline: %s", timeline);
+        return tasks;
+}
 
-        task = rtm_glib_tasks_add (priv->rtm_glib, timeline, "test-rtm-glib", NULL, FALSE, &error);
-        if (error != NULL) {
-                g_error ("%s", rtm_error_get_message (error));
-                goto auth_response_cb_OUT;
-        }
-        if (task != NULL) {
-                g_print ("First task added! task_id: %s\n", rtm_task_get_id (task));
-        } else {
-                g_print ("First task NOT added!\n");
-                goto auth_response_cb_OUT;
+RtmTask*
+milk_auth_task_add (MilkAuth    *auth,
+                    char        *timeline,
+                    const char  *name,
+                    GError     **error)
+{
+        MilkAuthPrivate *priv;
+
+        g_return_val_if_fail (MILK_IS_AUTH (auth), NULL);
+
+        priv = MILK_AUTH_PRIVATE (auth);
+
+        /* XXX: this uses Smart Add parsing; make this user-settable? */
+        /* XXX: the cast to char* is actually a bug in the rtm-glib API */
+        return rtm_glib_tasks_add (priv->rtm_glib, timeline, (char*) name, NULL,
+                        TRUE, error);
+}
+
+/* FIXME: we probably really want this to be async (but sequencable) */
+GList*
+milk_auth_tasks_send_changes (MilkAuth *auth,
+                              char     *timeline,
+                              GList    *tasks)
+{
+        gboolean success = TRUE;
+        MilkAuthPrivate *priv;
+        GList *l;
+        GList *tasks_sent = NULL;
+        GError *error = NULL;
+
+        g_return_val_if_fail (MILK_IS_AUTH (auth), NULL);
+        g_return_val_if_fail (tasks, NULL);
+
+        priv = MILK_AUTH_PRIVATE (auth);
+
+        for (l = tasks; l; l = l->next) {
+                RtmTask *task = l->data;
+
+                GTimeVal *tv;
+
+                /* If any of these conditions fail, libsoup ends up exploding
+                 * in a segfault (blindly de-reffing NULL); better to be safe
+                 * than sorry */
+                if (!rtm_task_get_list_id (task)) {
+                        g_warning (G_STRLOC ": task doesn't have a list ID; "
+                                        "skipping...");
+                        continue;
+                }
+
+                if (!rtm_task_get_taskseries_id (task)) {
+                        g_warning (G_STRLOC ": task doesn't have a taskseries "
+                                        "ID; skipping...");
+                        continue;
+                }
+
+                if (!rtm_task_get_id (task)) {
+                        g_warning (G_STRLOC ": task doesn't have an ID; "
+                                        "skipping...");
+                        continue;
+                }
+
+                tv = rtm_task_get_due_date (task);
+                if (tv) {
+                        char *due_str;
+                        char *tid;
+
+                        due_str = g_time_val_to_iso8601 (tv);
+
+                        /* FIXME: cut this */
+                        g_debug ("going to set due string: '%s'", due_str);
+
+                        /* XXX: this uses Smart Add parsing; make this
+                         * user-settable? */
+                        /* XXX: the cast to char* is actually a bug in the
+                         * rtm-glib API */
+                        tid = rtm_glib_tasks_set_due_date (priv->rtm_glib, timeline,
+                                        task, due_str,
+                                        /* FIXME: set this appropriately */
+                                        FALSE,
+                                        FALSE, &error);
+
+                        if (tid) {
+                                /* FIXME: this should be a set, not a list --
+                                 * we'll add each task to the set if it's been
+                                 * changed since the last send */
+                                tasks_sent = g_list_prepend (tasks_sent, task);
+                        } else {
+                                g_warning ("failed to add some tasks: %s",
+                                                error->message);
+                                g_clear_error (&error);
+                        }
+
+                        g_free (tid);
+                }
+
+                /* FIXME: handle all the other attributes, not just the date */
         }
 
-#endif
+        return tasks_sent;
+}
 
-auth_response_cb_OUT:
-        gtk_widget_destroy (dialog);
+char*
+milk_auth_task_complete (MilkAuth  *auth,
+                         char      *timeline,
+                         RtmTask   *task,
+                         GError   **error)
+{
+        MilkAuthPrivate *priv;
+
+        g_return_val_if_fail (MILK_IS_AUTH (auth), NULL);
+
+        priv = MILK_AUTH_PRIVATE (auth);
+
+        return rtm_glib_tasks_complete (priv->rtm_glib, timeline, task, error);
 }
 
-void
-milk_auth_run_demo (MilkAuth *auth)
+char*
+milk_auth_task_delete (MilkAuth  *auth,
+                       char      *timeline,
+                       RtmTask   *task,
+                       GError   **error)
 {
         MilkAuthPrivate *priv;
 
+        g_return_val_if_fail (MILK_IS_AUTH (auth), NULL);
+
+        priv = MILK_AUTH_PRIVATE (auth);
+
+        return rtm_glib_tasks_delete (priv->rtm_glib, timeline, task, error);
+}
+
+/* FIXME: why does this (or something above it) totally fail if we don't have a
+ * working Internet connection / resolv.conf is mangled? */
+/* FIXME: instead of this manual call, listen to the connection manager
+ * transitions -- see this:
+ * http://wiki.maemo.org/Documentation/Maemo_5_Developer_Guide/Using_Connectivity_Components/Maemo_Connectivity#Libconic_Usage
+ */
+void
+milk_auth_log_in (MilkAuth *auth)
+{
+        MilkAuthPrivate *priv;
         GError *error = NULL;
         gchar *url;
         GtkDialog *dialog;
 
+        g_return_if_fail (auth);
+        g_return_if_fail (MILK_IS_AUTH (auth));
+
         priv = MILK_AUTH_PRIVATE (auth);
 
         if (rtm_glib_test_echo (priv->rtm_glib, &error)) {
@@ -237,7 +442,6 @@ milk_auth_run_demo (MilkAuth *auth)
                         auth);
 }
 
-
 static void
 milk_auth_constructed (GObject *object)
 {
@@ -292,6 +496,18 @@ milk_auth_class_init (MilkAuthClass *klass)
                           RTM_SHARED_SECRET,
                           G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
                           G_PARAM_STATIC_STRINGS));
+
+        g_object_class_install_property
+                (object_class,
+                 PROP_STATE,
+                 g_param_spec_int
+                         ("state",
+                          "Authentication state",
+                          "Authentication/connection state with the server.",
+                          0, (NUM_MILK_AUTH_STATES-1),
+                          MILK_AUTH_STATE_DISCONNECTED,
+                          G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
+                          G_PARAM_STATIC_STRINGS));
 }
 
 static void