cosmetix
[k8lowj.git] / src / sync.c
blob3cc52f92d12d623702b2c1b70b059d51140b4c69
1 /* logjam - a GTK client for LiveJournal.
2 * Copyright (C) 2000-2003 Evan Martin <evan@livejournal.com>
3 */
4 #ifdef HAVE_GTK
5 # include "gtk-all.h"
6 #else
7 # include "glib-all.h"
8 #endif
10 #include <errno.h>
12 #include "liblj/sync.h"
14 #include "conf.h"
15 #include "journalstore.h"
16 #include "network.h"
17 #include "sync.h"
20 static const char *status_stages[] = {
21 "Entry metadata...",
22 "Entries...",
23 //N_("Comment metadata..."),
24 //N_("Comments..."),
28 typedef enum {
29 STAGE_ENTRYMETA,
30 STAGE_ENTRY,
31 //STAGE_COMMENTMETA,
32 //STAGE_COMMENT,
33 STAGE_COUNT
34 } StatusStage;
37 typedef struct {
38 #ifdef HAVE_GTK
39 GtkWidget *progresswin;
40 GtkWidget *label, *progress;
41 StatusStage stage;
42 #endif
43 JamAccountLJ *account;
44 JournalStore *js;
45 char *lastsync;
46 int synced;
47 int total;
48 gboolean sync_complete;
49 GSList *syncitems;
50 } SyncStatus;
53 static gboolean sync_run_internal (SyncStatus *status, LJRunVerbCallback sync_run_verb, LJSyncProgressCallback sync_progress, gpointer parent, GSList **warnings, GError **err);
56 /*** gtk-specific functions. ***/
57 #ifdef HAVE_GTK
58 static void show_status_stage (SyncStatus *status) {
59 GString *str = g_string_sized_new(20 *STAGE_COUNT);
60 for (int i = 0; i < STAGE_COUNT; ++i) {
61 if (i == status->stage) g_string_append(str, "\342\226\266 "); /* U+25B6: black arrow */
62 g_string_append(str, _(status_stages[i]));
63 g_string_append_c(str, '\n');
65 gtk_label_set_label(GTK_LABEL(status->label), str->str);
66 g_string_free(str, TRUE);
70 static void sync_init_gtk (SyncStatus *status, gpointer parent) {
71 status->progresswin = progress_window_new(GTK_WINDOW(parent), _("Synchronizing Journal"));
72 status->label = gtk_label_new("");
73 gtk_misc_set_alignment(GTK_MISC(status->label), 0, 0);
74 status->stage = 0;
75 show_status_stage(status);
76 status->progress = gtk_progress_bar_new();
77 gtk_widget_show(status->label);
78 gtk_widget_show(status->progress);
79 progress_window_pack(PROGRESS_WINDOW(status->progresswin), status->label);
80 progress_window_pack(PROGRESS_WINDOW(status->progresswin), status->progress);
81 gtk_widget_show(status->progresswin);
85 static gboolean sync_run_verb_gtk (gpointer data, LJVerb *verb, GError **err) {
86 SyncStatus *status = data;
87 return net_window_run_verb(PROGRESS_WINDOW(status->progresswin), verb);
91 static void sync_progress_gtk (gpointer data, LJSyncProgress progress, int cur, int max, const char *date) {
92 SyncStatus *status = data;
93 double fraction = 0.0;
94 StatusStage stage;
95 switch (progress) {
96 case LJ_SYNC_PROGRESS_ITEMS: stage = STAGE_ENTRYMETA; break;
97 case LJ_SYNC_PROGRESS_ENTRIES: stage = STAGE_ENTRY; break;
98 default: stage = STAGE_ENTRY; break; /*k8: just in case */
100 if (stage != status->stage) {
101 status->stage = stage;
102 show_status_stage(status);
104 if (max > 0) fraction = cur/(double)max;
105 gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(status->progress), fraction);
109 static void sync_show_warnings_gtk (SyncStatus *status, GSList *warnings) {
110 GtkWidget *dlg, *hbox, *image, *label, *scroll;
111 GSList *l;
112 GString *warnstr;
113 /* we create our own version of GtkMessageDialog so we can add the scroll bar */
114 dlg = gtk_dialog_new_with_buttons(_("Warnings"), GTK_WINDOW(status->progresswin), GTK_DIALOG_MODAL, GTK_STOCK_OK, GTK_RESPONSE_ACCEPT, NULL);
116 image = gtk_image_new_from_stock(GTK_STOCK_DIALOG_WARNING, GTK_ICON_SIZE_DIALOG);
117 gtk_misc_set_alignment(GTK_MISC(image), 0.5, 0.0);
119 warnstr = g_string_new(warnings->data);
120 for (l = warnings->next; l; l = l->next) {
121 g_string_append_c(warnstr, '\n');
122 g_string_append(warnstr, l->data);
125 label = gtk_label_new(warnstr->str);
126 g_string_free(warnstr, TRUE);
127 gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
128 gtk_label_set_selectable(GTK_LABEL(label), TRUE);
130 scroll = gtk_scrolled_window_new(NULL, NULL);
131 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
132 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scroll), GTK_SHADOW_NONE);
133 gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scroll), label);
135 hbox = gtk_hbox_new(FALSE, 6);
136 gtk_box_pack_start(GTK_BOX(hbox), image, FALSE, FALSE, 0);
137 gtk_box_pack_start(GTK_BOX(hbox), scroll, TRUE, TRUE, 0);
138 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dlg)->vbox), hbox, TRUE, TRUE, 0);
139 gtk_widget_show_all(hbox);
141 gtk_dialog_run(GTK_DIALOG(dlg));
142 gtk_widget_destroy(dlg);
146 gboolean sync_run_gtk (JamAccountLJ *acc, gpointer parent) {
147 SyncStatus st = { 0 }, *status = &st;
148 GSList *warnings = NULL;
149 GError *err = NULL;
150 gboolean success;
152 status->account = acc;
154 sync_init_gtk(status, parent);
155 success = sync_run_internal(status, sync_run_verb_gtk, sync_progress_gtk, parent, &warnings, &err);
157 if (warnings) {
158 sync_show_warnings_gtk(status, warnings);
159 g_slist_foreach(warnings, (GFunc) g_free, NULL);
160 g_slist_free(warnings);
163 if (err) {
164 progress_window_show_error(PROGRESS_WINDOW(status->progresswin), err->message);
165 g_error_free(err);
166 success = FALSE;
169 if (status->progresswin) gtk_widget_destroy(status->progresswin);
171 return success;
173 #endif /* HAVE_GTK */
176 /*** console-specific functions. ***/
177 static gboolean sync_run_verb_cli (gpointer data, LJVerb *verb, GError **err) {
178 return net_run_verb_ctx(verb, network_ctx_silent, err);
182 static void sync_progress_cli (gpointer data, LJSyncProgress progress, int cur, int max, const char *date) {
183 if (max == 0) {
184 if (cur == 0 && progress == LJ_SYNC_PROGRESS_ITEMS) g_print(_("Up-to-date.\n"));
185 return;
187 if (cur == 0) {
188 switch (progress) {
189 case LJ_SYNC_PROGRESS_ITEMS: g_print(_("Downloading %d sync items: "), max); break;
190 case LJ_SYNC_PROGRESS_ENTRIES: g_print(_("Downloading %d entries: "), max); break;
192 } else {
193 g_print("%.1f%% ", (cur*100.0)/(double)max);
194 if (cur == max) g_print(_("done.\n"));
199 gboolean sync_run_cli (JamAccountLJ *acc) {
200 SyncStatus st = { 0 }, *status = &st;
201 GSList *warnings = NULL, *l;
202 GError *err = NULL;
203 char *id;
204 gboolean success;
206 status->account = acc;
207 id = jam_account_id_strdup(JAM_ACCOUNT(status->account));
208 g_print(_("Synchronizing '%s'..."), id);
209 g_print("\n");
210 g_free(id);
212 success = sync_run_internal(status, sync_run_verb_cli, sync_progress_cli, NULL, &warnings, &err);
214 if (warnings) {
215 g_print(_("Warnings:\n"));
216 for (l = warnings; l; l = l->next) g_print("\t%s\n", (char *)l->data);
217 g_slist_foreach(warnings, (GFunc)g_free, NULL);
218 g_slist_free(warnings);
220 if (err) {
221 g_print(_("Error: %s\n"), err->message);
222 g_error_free(err);
223 success = FALSE;
225 return success;
229 static gboolean put_lastsync (gpointer data, const char *lastsync, GError **err) {
230 SyncStatus *status = data;
231 return journal_store_put_lastsync(status->js, lastsync, err);
235 static gboolean put_entries (gpointer data, LJEntry **entries, int count, GError **err) {
236 SyncStatus *status = data;
237 if (!journal_store_put_group(status->js, entries, count, err)) return FALSE;
238 return TRUE;
242 /* through callbacks, this function manages to drive both
243 * the gtk and the cli sync. */
244 static gboolean sync_run_internal (
245 SyncStatus *status,
246 LJRunVerbCallback sync_run_verb,
247 LJSyncProgressCallback sync_progress, gpointer parent, GSList **warnings, GError **err)
249 GError *tmperr = NULL;
250 gboolean success = FALSE;
251 char *lastsync = NULL;
253 status->js = journal_store_open(JAM_ACCOUNT(status->account), TRUE, &tmperr);
254 if (!status->js) goto err;
256 lastsync = journal_store_get_lastsync(status->js);
258 if (!lj_sync_run(jam_account_lj_get_user(status->account), NULL/*usejournal*/, lastsync, put_lastsync, sync_run_verb, put_entries, sync_progress, status, warnings, &tmperr)) goto err;
260 success = TRUE;
262 err:
263 if (tmperr) g_propagate_error(err, tmperr);
265 g_free(lastsync);
266 if (status->js) journal_store_free(status->js);
268 return success;
272 gboolean sync_run (JamAccountLJ *acc, gpointer parent) {
273 #ifdef HAVE_GTK
274 if (!app.cli) return sync_run_gtk(acc, parent);
275 return sync_run_cli(acc);
276 #else
277 return sync_run_cli(acc);
278 #endif