diff options
Diffstat (limited to 'src/visited.c')
-rw-r--r-- | src/visited.c | 128 |
1 files changed, 128 insertions, 0 deletions
diff --git a/src/visited.c b/src/visited.c new file mode 100644 index 00000000..af976be5 --- /dev/null +++ b/src/visited.c | |||
@@ -0,0 +1,128 @@ | |||
1 | #include "visited.h" | ||
2 | #include "app.h" | ||
3 | |||
4 | #include <the_Foundation/file.h> | ||
5 | #include <the_Foundation/path.h> | ||
6 | #include <the_Foundation/sortedarray.h> | ||
7 | |||
8 | static const size_t maxAgeVisited_Visited_ = 3600 * 24 * 30; /* one month */ | ||
9 | |||
10 | void init_VisitedUrl(iVisitedUrl *d) { | ||
11 | initCurrent_Time(&d->when); | ||
12 | init_String(&d->url); | ||
13 | } | ||
14 | |||
15 | void deinit_VisitedUrl(iVisitedUrl *d) { | ||
16 | deinit_String(&d->url); | ||
17 | } | ||
18 | |||
19 | static int cmpUrl_VisitedUrl_(const void *a, const void *b) { | ||
20 | return cmpString_String(&((const iVisitedUrl *) a)->url, &((const iVisitedUrl *) b)->url); | ||
21 | } | ||
22 | |||
23 | static int cmpNewer_VisitedUrl_(const void *insert, const void *existing) { | ||
24 | return seconds_Time(&((const iVisitedUrl *) insert )->when) > | ||
25 | seconds_Time(&((const iVisitedUrl *) existing)->when); | ||
26 | } | ||
27 | |||
28 | /*----------------------------------------------------------------------------------------------*/ | ||
29 | |||
30 | struct Impl_Visited { | ||
31 | iSortedArray visited; | ||
32 | }; | ||
33 | |||
34 | iDefineTypeConstruction(Visited) | ||
35 | |||
36 | void init_Visited(iVisited *d) { | ||
37 | init_SortedArray(&d->visited, sizeof(iVisitedUrl), cmpUrl_VisitedUrl_); | ||
38 | } | ||
39 | |||
40 | void deinit_Visited(iVisited *d) { | ||
41 | clear_Visited(d); | ||
42 | deinit_SortedArray(&d->visited); | ||
43 | } | ||
44 | |||
45 | void save_Visited(const iVisited *d, const char *dirPath) { | ||
46 | iString *line = new_String(); | ||
47 | iFile *f = newCStr_File(concatPath_CStr(dirPath, "visited.txt")); | ||
48 | if (open_File(f, writeOnly_FileMode | text_FileMode)) { | ||
49 | iConstForEach(Array, i, &d->visited.values) { | ||
50 | const iVisitedUrl *item = i.value; | ||
51 | iDate date; | ||
52 | init_Date(&date, &item->when); | ||
53 | format_String(line, | ||
54 | "%04d-%02d-%02dT%02d:%02d:%02d %s\n", | ||
55 | date.year, | ||
56 | date.month, | ||
57 | date.day, | ||
58 | date.hour, | ||
59 | date.minute, | ||
60 | date.second, | ||
61 | cstr_String(&item->url)); | ||
62 | writeData_File(f, cstr_String(line), size_String(line)); | ||
63 | } | ||
64 | } | ||
65 | iRelease(f); | ||
66 | delete_String(line); | ||
67 | } | ||
68 | |||
69 | void load_Visited(iVisited *d, const char *dirPath) { | ||
70 | iFile *f = newCStr_File(concatPath_CStr(dirPath, "visited.txt")); | ||
71 | if (open_File(f, readOnly_FileMode | text_FileMode)) { | ||
72 | const iRangecc src = range_Block(collect_Block(readAll_File(f))); | ||
73 | iRangecc line = iNullRange; | ||
74 | iTime now; | ||
75 | initCurrent_Time(&now); | ||
76 | while (nextSplit_Rangecc(&src, "\n", &line)) { | ||
77 | int y, m, D, H, M, S; | ||
78 | sscanf(line.start, "%04d-%02d-%02dT%02d:%02d:%02d ", &y, &m, &D, &H, &M, &S); | ||
79 | if (!y) break; | ||
80 | iVisitedUrl item; | ||
81 | init_VisitedUrl(&item); | ||
82 | init_Time( | ||
83 | &item.when, | ||
84 | &(iDate){ .year = y, .month = m, .day = D, .hour = H, .minute = M, .second = S }); | ||
85 | if (secondsSince_Time(&now, &item.when) > maxAgeVisited_Visited_) { | ||
86 | continue; /* Too old. */ | ||
87 | } | ||
88 | initRange_String(&item.url, (iRangecc){ line.start + 20, line.end }); | ||
89 | insert_SortedArray(&d->visited, &item); | ||
90 | } | ||
91 | } | ||
92 | iRelease(f); | ||
93 | } | ||
94 | |||
95 | void clear_Visited(iVisited *d) { | ||
96 | iForEach(Array, v, &d->visited.values) { | ||
97 | deinit_VisitedUrl(v.value); | ||
98 | } | ||
99 | clear_SortedArray(&d->visited); | ||
100 | } | ||
101 | |||
102 | void visitUrl_Visited(iVisited *d, const iString *url) { | ||
103 | iVisitedUrl visit; | ||
104 | init_VisitedUrl(&visit); | ||
105 | set_String(&visit.url, url); | ||
106 | size_t pos; | ||
107 | if (locate_SortedArray(&d->visited, &visit, &pos)) { | ||
108 | iVisitedUrl *old = at_SortedArray(&d->visited, pos); | ||
109 | if (cmpNewer_VisitedUrl_(&visit, old)) { | ||
110 | old->when = visit.when; | ||
111 | deinit_VisitedUrl(&visit); | ||
112 | return; | ||
113 | } | ||
114 | } | ||
115 | insert_SortedArray(&d->visited, &visit); | ||
116 | } | ||
117 | |||
118 | iTime urlVisitTime_Visited(const iVisited *d, const iString *url) { | ||
119 | iVisitedUrl item; | ||
120 | size_t pos; | ||
121 | iZap(item); | ||
122 | initCopy_String(&item.url, url); | ||
123 | if (locate_SortedArray(&d->visited, &item, &pos)) { | ||
124 | item.when = ((const iVisitedUrl *) constAt_SortedArray(&d->visited, pos))->when; | ||
125 | } | ||
126 | deinit_String(&item.url); | ||
127 | return item.when; | ||
128 | } | ||