summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/app.c8
-rw-r--r--src/bookmarks.c111
-rw-r--r--src/bookmarks.h5
-rw-r--r--src/ui/sidebarwidget.c23
-rw-r--r--src/ui/util.c8
-rw-r--r--src/ui/window.c1
6 files changed, 147 insertions, 9 deletions
diff --git a/src/app.c b/src/app.c
index 77fbf430..4ea37cd4 100644
--- a/src/app.c
+++ b/src/app.c
@@ -1363,6 +1363,14 @@ iBool handleCommand_App(const char *cmd) {
1363 makeFeedSettings_Widget(findUrl_Bookmarks(d->bookmarks, url)); 1363 makeFeedSettings_Widget(findUrl_Bookmarks(d->bookmarks, url));
1364 return iTrue; 1364 return iTrue;
1365 } 1365 }
1366 else if (equal_Command(cmd, "bookmarks.reload.remote")) {
1367 fetchRemote_Bookmarks(bookmarks_App());
1368 return iTrue;
1369 }
1370 else if (equal_Command(cmd, "bookmarks.request.finished")) {
1371 requestFinished_Bookmarks(bookmarks_App(), pointerLabel_Command(cmd, "req"));
1372 return iTrue;
1373 }
1366 else if (equal_Command(cmd, "bookmarks.changed")) { 1374 else if (equal_Command(cmd, "bookmarks.changed")) {
1367 save_Bookmarks(d->bookmarks, dataDir_App_); 1375 save_Bookmarks(d->bookmarks, dataDir_App_);
1368 return iFalse; 1376 return iFalse;
diff --git a/src/bookmarks.c b/src/bookmarks.c
index 72c5ad04..27909349 100644
--- a/src/bookmarks.c
+++ b/src/bookmarks.c
@@ -22,6 +22,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
22 22
23#include "bookmarks.h" 23#include "bookmarks.h"
24#include "visited.h" 24#include "visited.h"
25#include "gmrequest.h"
25#include "app.h" 26#include "app.h"
26 27
27#include <the_Foundation/file.h> 28#include <the_Foundation/file.h>
@@ -82,9 +83,10 @@ static int cmpTitleAscending_Bookmark_(const iBookmark **a, const iBookmark **b)
82static const char *fileName_Bookmarks_ = "bookmarks.txt"; 83static const char *fileName_Bookmarks_ = "bookmarks.txt";
83 84
84struct Impl_Bookmarks { 85struct Impl_Bookmarks {
85 iMutex *mtx; 86 iMutex * mtx;
86 int idEnum; 87 int idEnum;
87 iHash bookmarks; /* bookmark ID is the hash key */ 88 iHash bookmarks; /* bookmark ID is the hash key */
89 iPtrArray remoteRequests;
88}; 90};
89 91
90iDefineTypeConstruction(Bookmarks) 92iDefineTypeConstruction(Bookmarks)
@@ -93,9 +95,15 @@ void init_Bookmarks(iBookmarks *d) {
93 d->mtx = new_Mutex(); 95 d->mtx = new_Mutex();
94 d->idEnum = 0; 96 d->idEnum = 0;
95 init_Hash(&d->bookmarks); 97 init_Hash(&d->bookmarks);
98 init_PtrArray(&d->remoteRequests);
96} 99}
97 100
98void deinit_Bookmarks(iBookmarks *d) { 101void deinit_Bookmarks(iBookmarks *d) {
102 iForEach(PtrArray, i, &d->remoteRequests) {
103 cancel_GmRequest(i.ptr);
104 iRelease(i.ptr);
105 }
106 deinit_PtrArray(&d->remoteRequests);
99 clear_Bookmarks(d); 107 clear_Bookmarks(d);
100 deinit_Hash(&d->bookmarks); 108 deinit_Hash(&d->bookmarks);
101 delete_Mutex(d->mtx); 109 delete_Mutex(d->mtx);
@@ -154,15 +162,23 @@ void load_Bookmarks(iBookmarks *d, const char *dirPath) {
154 } 162 }
155 } 163 }
156 iRelease(f); 164 iRelease(f);
165 fetchRemote_Bookmarks(d);
157} 166}
158 167
159void save_Bookmarks(const iBookmarks *d, const char *dirPath) { 168void save_Bookmarks(const iBookmarks *d, const char *dirPath) {
160 lock_Mutex(d->mtx); 169 lock_Mutex(d->mtx);
170 iRegExp *remotePattern = iClob(new_RegExp("\\bremote\\b", caseSensitive_RegExpOption));
161 iFile *f = newCStr_File(concatPath_CStr(dirPath, fileName_Bookmarks_)); 171 iFile *f = newCStr_File(concatPath_CStr(dirPath, fileName_Bookmarks_));
162 if (open_File(f, writeOnly_FileMode | text_FileMode)) { 172 if (open_File(f, writeOnly_FileMode | text_FileMode)) {
163 iString *str = collectNew_String(); 173 iString *str = collectNew_String();
164 iConstForEach(Hash, i, &d->bookmarks) { 174 iConstForEach(Hash, i, &d->bookmarks) {
165 const iBookmark *bm = (const iBookmark *) i.value; 175 const iBookmark *bm = (const iBookmark *) i.value;
176 iRegExpMatch m;
177 init_RegExpMatch(&m);
178 if (matchString_RegExp(remotePattern, &bm->tags, &m)) {
179 /* Remote bookmarks are not saved. */
180 continue;
181 }
166 format_String(str, 182 format_String(str,
167 "%08x %lf %s\n%s\n%s\n", 183 "%08x %lf %s\n%s\n%s\n",
168 bm->icon, 184 bm->icon,
@@ -327,3 +343,92 @@ const iString *bookmarkListPage_Bookmarks(const iBookmarks *d, enum iBookmarkLis
327 } 343 }
328 return str; 344 return str;
329} 345}
346
347static iBool isRemoteSource_Bookmark_(void *context, const iBookmark *d) {
348 iUnused(context);
349 return hasTag_Bookmark(d, "remotesource");
350}
351
352void remoteRequestFinished_Bookmarks_(iBookmarks *d, iGmRequest *req) {
353 iUnused(d);
354 postCommandf_App("bookmarks.request.finished req:%p", req);
355}
356
357void requestFinished_Bookmarks(iBookmarks *d, iGmRequest *req) {
358 iBool found = iFalse;
359 iForEach(PtrArray, i, &d->remoteRequests) {
360 if (i.ptr == req) {
361 remove_PtrArrayIterator(&i);
362 found = iTrue;
363 break;
364 }
365 }
366 iAssert(found);
367 /* Parse all links in the result. */
368 if (isSuccess_GmStatusCode(status_GmRequest(req))) {
369 iTime now;
370 initCurrent_Time(&now);
371 iRegExp *linkPattern = new_RegExp("^=>\\s*([^\\s]+)\\s+(.*)", 0);
372 iString src;
373 const iString *remoteTag = collectNewCStr_String("remote");
374 initBlock_String(&src, body_GmRequest(req));
375 iRangecc srcLine = iNullRange;
376 while (nextSplit_Rangecc(range_String(&src), "\n", &srcLine)) {
377 iRangecc line = srcLine;
378 trimEnd_Rangecc(&line);
379 iRegExpMatch m;
380 init_RegExpMatch(&m);
381 if (matchRange_RegExp(linkPattern, line, &m)) {
382 const iRangecc url = capturedRange_RegExpMatch(&m, 1);
383 const iRangecc title = capturedRange_RegExpMatch(&m, 2);
384 iString * urlStr = newRange_String(url);
385 const iString *absUrl = absoluteUrl_String(url_GmRequest(req), urlStr);
386 if (!findUrl_Bookmarks(d, absUrl)) {
387 iString *titleStr = newRange_String(title);
388 add_Bookmarks(d, absUrl, titleStr, remoteTag, 0x2601 /* cloud */);
389 delete_String(titleStr);
390 }
391 delete_String(urlStr);
392 }
393 }
394 deinit_String(&src);
395 iRelease(linkPattern);
396 }
397 else {
398 /* TODO: Show error? */
399 }
400 iRelease(req);
401 if (isEmpty_PtrArray(&d->remoteRequests)) {
402 postCommand_App("bookmarks.changed");
403 }
404}
405
406void fetchRemote_Bookmarks(iBookmarks *d) {
407 if (!isEmpty_PtrArray(&d->remoteRequests)) {
408 return; /* Already ongoing. */
409 }
410 lock_Mutex(d->mtx);
411 /* Remove all current remote bookmarks. */ {
412 size_t numRemoved = 0;
413 iForEach(Hash, i, &d->bookmarks) {
414 iBookmark *bm = (iBookmark *) i.value;
415 if (hasTag_Bookmark(bm, "remote")) {
416 delete_Bookmark(bm);
417 remove_HashIterator(&i);
418 numRemoved++;
419 }
420 }
421 if (numRemoved) {
422 postCommand_App("bookmarks.changed");
423 }
424 }
425 iConstForEach(PtrArray, i, list_Bookmarks(d, NULL, isRemoteSource_Bookmark_, NULL)) {
426 const iBookmark *bm = i.ptr;
427 iGmRequest *req = new_GmRequest(certs_App());
428 pushBack_PtrArray(&d->remoteRequests, req);
429 setUrl_GmRequest(req, &bm->url);
430 iConnect(GmRequest, req, finished, req, remoteRequestFinished_Bookmarks_);
431 submit_GmRequest(req);
432 }
433 unlock_Mutex(d->mtx);
434}
diff --git a/src/bookmarks.h b/src/bookmarks.h
index 8273d7bc..2975b082 100644
--- a/src/bookmarks.h
+++ b/src/bookmarks.h
@@ -27,6 +27,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
27#include <the_Foundation/string.h> 27#include <the_Foundation/string.h>
28#include <the_Foundation/time.h> 28#include <the_Foundation/time.h>
29 29
30iDeclareType(GmRequest)
31
30iDeclareType(Bookmark) 32iDeclareType(Bookmark)
31iDeclareTypeConstruction(Bookmark) 33iDeclareTypeConstruction(Bookmark)
32 34
@@ -54,6 +56,9 @@ void clear_Bookmarks (iBookmarks *);
54void load_Bookmarks (iBookmarks *, const char *dirPath); 56void load_Bookmarks (iBookmarks *, const char *dirPath);
55void save_Bookmarks (const iBookmarks *, const char *dirPath); 57void save_Bookmarks (const iBookmarks *, const char *dirPath);
56 58
59void fetchRemote_Bookmarks (iBookmarks *);
60void requestFinished_Bookmarks (iBookmarks *, iGmRequest *req);
61
57void add_Bookmarks (iBookmarks *, const iString *url, const iString *title, 62void add_Bookmarks (iBookmarks *, const iString *url, const iString *title,
58 const iString *tags, iChar icon); 63 const iString *tags, iChar icon);
59iBool remove_Bookmarks (iBookmarks *, uint32_t id); 64iBool remove_Bookmarks (iBookmarks *, uint32_t id);
diff --git a/src/ui/sidebarwidget.c b/src/ui/sidebarwidget.c
index c2672646..3b7e7d4b 100644
--- a/src/ui/sidebarwidget.c
+++ b/src/ui/sidebarwidget.c
@@ -199,6 +199,7 @@ static void updateItems_SidebarWidget_(iSidebarWidget *d) {
199 case bookmarks_SidebarMode: { 199 case bookmarks_SidebarMode: {
200 iRegExp *homeTag = iClob(new_RegExp("\\bhomepage\\b", caseSensitive_RegExpOption)); 200 iRegExp *homeTag = iClob(new_RegExp("\\bhomepage\\b", caseSensitive_RegExpOption));
201 iRegExp *subTag = iClob(new_RegExp("\\bsubscribed\\b", caseSensitive_RegExpOption)); 201 iRegExp *subTag = iClob(new_RegExp("\\bsubscribed\\b", caseSensitive_RegExpOption));
202 iRegExp *remoteSourceTag = iClob(new_RegExp("\\bremotesource\\b", caseSensitive_RegExpOption));
202 iConstForEach(PtrArray, i, list_Bookmarks(bookmarks_App(), cmpTitle_Bookmark_, NULL, NULL)) { 203 iConstForEach(PtrArray, i, list_Bookmarks(bookmarks_App(), cmpTitle_Bookmark_, NULL, NULL)) {
203 const iBookmark *bm = i.ptr; 204 const iBookmark *bm = i.ptr;
204 iSidebarItem *item = new_SidebarItem(); 205 iSidebarItem *item = new_SidebarItem();
@@ -216,6 +217,10 @@ static void updateItems_SidebarWidget_(iSidebarWidget *d) {
216 if (matchString_RegExp(homeTag, &bm->tags, &m)) { 217 if (matchString_RegExp(homeTag, &bm->tags, &m)) {
217 appendChar_String(&item->meta, 0x1f3e0); 218 appendChar_String(&item->meta, 0x1f3e0);
218 } 219 }
220 init_RegExpMatch(&m);
221 if (matchString_RegExp(remoteSourceTag, &bm->tags, &m)) {
222 appendChar_String(&item->meta, 0x2601);
223 }
219 } 224 }
220 addItem_ListWidget(d->list, item); 225 addItem_ListWidget(d->list, item);
221 iRelease(item); 226 iRelease(item);
@@ -228,11 +233,14 @@ static void updateItems_SidebarWidget_(iSidebarWidget *d) {
228 { "Edit Bookmark...", 0, 0, "bookmark.edit" }, 233 { "Edit Bookmark...", 0, 0, "bookmark.edit" },
229 { "Copy URL", 0, 0, "bookmark.copy" }, 234 { "Copy URL", 0, 0, "bookmark.copy" },
230 { "---", 0, 0, NULL }, 235 { "---", 0, 0, NULL },
231 { "Subscribe to Feed", 0, 0, "bookmark.tag tag:subscribed" }, 236 { "?", 0, 0, "bookmark.tag tag:subscribed" },
232 { "", 0, 0, "bookmark.tag tag:homepage" }, 237 { "?", 0, 0, "bookmark.tag tag:homepage" },
238 { "?", 0, 0, "bookmark.tag tag:remotesource" },
239 { "---", 0, 0, NULL },
240 { uiTextCaution_ColorEscape "Delete Bookmark", 0, 0, "bookmark.delete" },
233 { "---", 0, 0, NULL }, 241 { "---", 0, 0, NULL },
234 { uiTextCaution_ColorEscape "Delete Bookmark", 0, 0, "bookmark.delete" } }, 242 { "Refresh Remote Bookmarks", 0, 0, "bookmarks.reload.remote" } },
235 10); 243 13);
236 break; 244 break;
237 } 245 }
238 case history_SidebarMode: { 246 case history_SidebarMode: {
@@ -1006,6 +1014,13 @@ static iBool processEvent_SidebarWidget_(iSidebarWidget *d, const SDL_Event *ev)
1006 ? "Unsubscribe from Feed" 1014 ? "Unsubscribe from Feed"
1007 : "Subscribe to Feed"); 1015 : "Subscribe to Feed");
1008 } 1016 }
1017 menuItem = findMenuItem_Widget(d->menu, "bookmark.tag tag:remotesource");
1018 if (menuItem) {
1019 setTextCStr_LabelWidget(menuItem,
1020 hasTag_Bookmark(bm, "remotesource")
1021 ? "Remove Bookmark Source"
1022 : "Use as Bookmark Source");
1023 }
1009 } 1024 }
1010 } 1025 }
1011 else if (d->mode == feeds_SidebarMode && d->contextItem) { 1026 else if (d->mode == feeds_SidebarMode && d->contextItem) {
diff --git a/src/ui/util.c b/src/ui/util.c
index 9bd40e80..1118758b 100644
--- a/src/ui/util.c
+++ b/src/ui/util.c
@@ -376,7 +376,9 @@ iWidget *addAction_Widget(iWidget *parent, int key, int kmods, const char *comma
376static iBool isCommandIgnoredByMenus_(const char *cmd) { 376static iBool isCommandIgnoredByMenus_(const char *cmd) {
377 return equal_Command(cmd, "media.updated") || equal_Command(cmd, "media.player.update") || 377 return equal_Command(cmd, "media.updated") || equal_Command(cmd, "media.player.update") ||
378 startsWith_CStr(cmd, "feeds.update.") || 378 startsWith_CStr(cmd, "feeds.update.") ||
379 equal_Command(cmd, "document.request.updated") || equal_Command(cmd, "window.resized") || 379 equal_Command(cmd, "document.request.updated") ||
380 equal_Command(cmd, "bookmarks.request.finished") ||
381 equal_Command(cmd, "window.resized") ||
380 equal_Command(cmd, "window.reload.update") || 382 equal_Command(cmd, "window.reload.update") ||
381 (equal_Command(cmd, "mouse.clicked") && !arg_Command(cmd)); /* button released */ 383 (equal_Command(cmd, "mouse.clicked") && !arg_Command(cmd)); /* button released */
382} 384}
@@ -893,7 +895,9 @@ void updateValueInput_Widget(iWidget *d, const char *title, const char *prompt)
893 895
894static iBool messageHandler_(iWidget *msg, const char *cmd) { 896static iBool messageHandler_(iWidget *msg, const char *cmd) {
895 /* Almost any command dismisses the sheet. */ 897 /* Almost any command dismisses the sheet. */
896 if (!(equal_Command(cmd, "media.updated") || equal_Command(cmd, "media.player.update") || 898 if (!(equal_Command(cmd, "media.updated") ||
899 equal_Command(cmd, "media.player.update") ||
900 equal_Command(cmd, "bookmarks.request.finished") ||
897 equal_Command(cmd, "document.request.updated") || startsWith_CStr(cmd, "window."))) { 901 equal_Command(cmd, "document.request.updated") || startsWith_CStr(cmd, "window."))) {
898 destroy_Widget(msg); 902 destroy_Widget(msg);
899 } 903 }
diff --git a/src/ui/window.c b/src/ui/window.c
index 6ec4a4f1..bc0a622e 100644
--- a/src/ui/window.c
+++ b/src/ui/window.c
@@ -167,6 +167,7 @@ static iMenuItem bookmarksMenuItems_[] = {
167 { "List All", 0, 0, "open url:about:bookmarks" }, 167 { "List All", 0, 0, "open url:about:bookmarks" },
168 { "List by Tag", 0, 0, "open url:about:bookmarks?tags" }, 168 { "List by Tag", 0, 0, "open url:about:bookmarks?tags" },
169 { "List by Creation Time", 0, 0, "open url:about:bookmarks?created" }, 169 { "List by Creation Time", 0, 0, "open url:about:bookmarks?created" },
170 { "Refresh Remote Bookmarks", 0, 0, "bookmarks.reload.remote" },
170 { "---", 0, 0, NULL }, 171 { "---", 0, 0, NULL },
171 { "Subscribe to This Page...", subscribeToPage_KeyModifier, "feeds.subscribe" }, 172 { "Subscribe to This Page...", subscribeToPage_KeyModifier, "feeds.subscribe" },
172 { "---", 0, 0, NULL }, 173 { "---", 0, 0, NULL },