'smart qotes' now will replace '<', '>' and '&' inside 'pre' and 'code' tags
[k8lowj.git] / src / sync.c
blob7c46394251cfdcb0d43058a202386a1a3c1cf4d6
1 /* logjam - a GTK client for LiveJournal.
2 * Copyright (C) 2000-2003 Evan Martin <evan@livejournal.com>
4 * vim: tabstop=4 shiftwidth=4 noexpandtab :
5 */
7 #ifdef HAVE_GTK
8 # include "gtk-all.h"
9 #else
10 # include "glib-all.h"
11 #endif
12 #include <errno.h>
14 #include "liblj/sync.h"
16 #include "conf.h"
17 #include "journalstore.h"
18 #include "network.h"
19 #include "sync.h"
21 static const char *status_stages[] = {
22 "Entry metadata...",
23 "Entries...",
24 //N_("Comment metadata..."),
25 //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,
156 parent, &warnings, &err);
158 if (warnings) {
159 sync_show_warnings_gtk(status, warnings);
160 g_slist_foreach(warnings, (GFunc)g_free, NULL);
161 g_slist_free(warnings);
164 if (err) {
165 progress_window_show_error(PROGRESS_WINDOW(status->progresswin), err->message);
166 g_error_free(err);
167 success = FALSE;
170 if (status->progresswin) gtk_widget_destroy(status->progresswin);
172 return success;
174 #endif /* HAVE_GTK */
177 /*** console-specific functions. ***/
178 static gboolean sync_run_verb_cli (gpointer data, LJVerb *verb, GError **err) {
179 return net_run_verb_ctx(verb, network_ctx_silent, err);
183 static void sync_progress_cli (gpointer data, LJSyncProgress progress, int cur, int max, const char *date) {
184 if (max == 0) {
185 if (cur == 0 && progress == LJ_SYNC_PROGRESS_ITEMS) g_print(_("Up-to-date.\n"));
186 return;
188 if (cur == 0) {
189 switch (progress) {
190 case LJ_SYNC_PROGRESS_ITEMS: g_print(_("Downloading %d sync items: "), max); break;
191 case LJ_SYNC_PROGRESS_ENTRIES: g_print(_("Downloading %d entries: "), max); break;
193 } else {
194 g_print("%.1f%% ", (cur*100.0)/(double)max);
195 if (cur == max) g_print(_("done.\n"));
200 gboolean sync_run_cli (JamAccountLJ *acc) {
201 SyncStatus st = {0}, *status = &st;
202 GSList *warnings = NULL, *l;
203 GError *err = NULL;
204 char *id;
205 gboolean success;
207 status->account = acc;
208 id = jam_account_id_strdup(JAM_ACCOUNT(status->account));
209 g_print(_("Synchronizing '%s'..."), id);
210 g_print("\n");
211 g_free(id);
213 success = sync_run_internal(status, sync_run_verb_cli, sync_progress_cli, NULL, &warnings, &err);
215 if (warnings) {
216 g_print(_("Warnings:\n"));
217 for (l = warnings; l; l = l->next) g_print("\t%s\n", (char*)l->data);
218 g_slist_foreach(warnings, (GFunc)g_free, NULL);
219 g_slist_free(warnings);
221 if (err) {
222 g_print(_("Error: %s\n"), err->message);
223 g_error_free(err);
224 success = FALSE;
226 return success;
230 static gboolean put_lastsync (gpointer data, const char *lastsync, GError **err) {
231 SyncStatus *status = data;
232 return journal_store_put_lastsync(status->js, lastsync, err);
236 static gboolean put_entries (gpointer data, LJEntry **entries, int count, GError **err) {
237 SyncStatus *status = data;
238 if (!journal_store_put_group(status->js, entries, count, err)) return FALSE;
239 return TRUE;
243 /* through callbacks, this function manages to drive both
244 * the gtk and the cli sync. */
245 static gboolean sync_run_internal (SyncStatus *status,
246 LJRunVerbCallback sync_run_verb,
247 LJSyncProgressCallback sync_progress,
248 gpointer parent,
249 GSList **warnings, GError **err)
251 GError *tmperr = NULL;
252 gboolean success = FALSE;
253 char *lastsync = NULL;
255 status->js = journal_store_open(JAM_ACCOUNT(status->account), TRUE, &tmperr);
256 if (!status->js) goto err;
258 lastsync = journal_store_get_lastsync(status->js);
260 if (!lj_sync_run(jam_account_lj_get_user(status->account), NULL/*usejournal*/,
261 lastsync,
262 put_lastsync, sync_run_verb, put_entries, sync_progress,
263 status, warnings, &tmperr))
264 goto err;
266 success = TRUE;
268 err:
269 if (tmperr) g_propagate_error(err, tmperr);
271 g_free(lastsync);
272 if (status->js) journal_store_free(status->js);
274 return success;
278 gboolean sync_run (JamAccountLJ *acc, gpointer parent) {
279 #ifdef HAVE_GTK
280 if (!app.cli) return sync_run_gtk(acc, parent);
281 else return sync_run_cli(acc);
282 #else
283 return sync_run_cli(acc);
284 #endif