annotate persistent-tags.sl @ 1:49f639bc9bd9 default tip

Change license to GPL-2.0+
author Guido Berhoerster <guido+slrn@berhoerster.name>
date Sat, 25 Jul 2015 17:12:29 +0200
parents 8eeb70d3d1ce
children
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
0
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
1 % persistent-tags.sl - keep persistent tags across sessions
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
2 %
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
3 % Copyright (C) 2009 Guido Berhoerster <guido+slrn@berhoerster.name>
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
4 %
1
49f639bc9bd9 Change license to GPL-2.0+
Guido Berhoerster <guido+slrn@berhoerster.name>
parents: 0
diff changeset
5 % This program is free software; you can redistribute it and/or
49f639bc9bd9 Change license to GPL-2.0+
Guido Berhoerster <guido+slrn@berhoerster.name>
parents: 0
diff changeset
6 % modify it under the terms of the GNU General Public License
49f639bc9bd9 Change license to GPL-2.0+
Guido Berhoerster <guido+slrn@berhoerster.name>
parents: 0
diff changeset
7 % as published by the Free Software Foundation; either version 2
49f639bc9bd9 Change license to GPL-2.0+
Guido Berhoerster <guido+slrn@berhoerster.name>
parents: 0
diff changeset
8 % of the License, or (at your option) any later version.
0
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
9 %
1
49f639bc9bd9 Change license to GPL-2.0+
Guido Berhoerster <guido+slrn@berhoerster.name>
parents: 0
diff changeset
10 % This program is distributed in the hope that it will be useful,
49f639bc9bd9 Change license to GPL-2.0+
Guido Berhoerster <guido+slrn@berhoerster.name>
parents: 0
diff changeset
11 % but WITHOUT ANY WARRANTY; without even the implied warranty of
49f639bc9bd9 Change license to GPL-2.0+
Guido Berhoerster <guido+slrn@berhoerster.name>
parents: 0
diff changeset
12 % MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
49f639bc9bd9 Change license to GPL-2.0+
Guido Berhoerster <guido+slrn@berhoerster.name>
parents: 0
diff changeset
13 % GNU General Public License for more details.
0
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
14 %
1
49f639bc9bd9 Change license to GPL-2.0+
Guido Berhoerster <guido+slrn@berhoerster.name>
parents: 0
diff changeset
15 % You should have received a copy of the GNU General Public License
49f639bc9bd9 Change license to GPL-2.0+
Guido Berhoerster <guido+slrn@berhoerster.name>
parents: 0
diff changeset
16 % along with this program; if not, write to the Free Software
49f639bc9bd9 Change license to GPL-2.0+
Guido Berhoerster <guido+slrn@berhoerster.name>
parents: 0
diff changeset
17 % Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
0
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
18
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
19 %open_log_file(make_home_filename("slrn-debug.log"));
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
20 %_traceback = 1;
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
21
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
22 implements("PersistentTags");
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
23
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
24 private variable rand_next = 1;
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
25
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
26 % implementation of rand based on an example in IEEE Std 1003.1, 2004 Edition
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
27 static define myrand() {
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
28 rand_next = rand_next * 1103515245 + 12345;
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
29 % RAND_MAX is hardcoded to 32767
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
30 return ((rand_next / 65536U) mod 32768U);
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
31 }
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
32
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
33 static define mysrand(seed) {
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
34 rand_next = seed;
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
35 }
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
36
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
37 private variable URL_SAFE_CHARS =
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
38 "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ.-+";
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
39
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
40 private define urldecode(str)
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
41 {
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
42 variable decoded_str = ""B;
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
43 variable char;
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
44 variable pos = 1;
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
45 variable opos = 1;
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
46
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
47 forever {
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
48 pos = string_match(str, "%[0-9a-fA-F][0-9a-fA-F]", opos);
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
49 if (pos == 0)
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
50 break;
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
51
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
52 % add characters between the last match and the current match
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
53 decoded_str += substr(str, opos, pos - opos);
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
54 % convert the hex representation of a byte to a byte and append it to
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
55 % the string
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
56 char = integer("0x" + substr(str, pos + 1, 2));
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
57 decoded_str += pack("C", char);
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
58 opos = pos + 3;
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
59 }
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
60 % add remaining charcters
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
61 decoded_str += substr(str, opos, -1);
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
62 return typecast(decoded_str, String_Type);
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
63 }
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
64
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
65 private define urlencode(str)
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
66 {
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
67 variable char;
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
68 variable encoded_str = "";
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
69 variable i;
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
70 variable j;
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
71
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
72 for (i = 0; i < strlen(str); ++i) {
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
73 char = substr(str, i + 1, 1);
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
74 ifnot (is_substr(URL_SAFE_CHARS, char)) {
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
75 for (j = 0; j < strbytelen(char); ++j) {
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
76 encoded_str += sprintf("%%%02X", char[j]);
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
77 }
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
78 } else {
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
79 encoded_str += sprintf("%s", char);
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
80 }
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
81 }
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
82 return encoded_str;
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
83 }
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
84
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
85 private variable FILENAME_CHARS =
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
86 "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
87 private variable FILENAME_CHARS_LEN = strlen(FILENAME_CHARS);
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
88
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
89 private define mkstemp(template)
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
90 {
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
91 variable fd;
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
92 variable tmp_filename;
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
93 variable len_template = strlen(@template);
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
94 variable c;
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
95
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
96 if (len_template < 6)
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
97 return NULL;
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
98 c = len_template - 6;
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
99 ifnot (substr(@template, c + 1, len_template) == "XXXXXX")
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
100 return NULL;
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
101
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
102 loop (10000) {
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
103 tmp_filename = substr(@template, 1, c);
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
104 loop(6) {
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
105 tmp_filename += FILENAME_CHARS[[myrand() mod FILENAME_CHARS_LEN]];
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
106 }
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
107 fd = open(tmp_filename, O_CREAT|O_EXCL|O_RDWR, 0600);
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
108 ifnot (fd == NULL) {
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
109 @template = tmp_filename;
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
110 break;
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
111 }
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
112 }
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
113
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
114 return fd;
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
115 }
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
116
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
117 private define lock_file(filename)
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
118 {
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
119 variable fd;
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
120 variable st;
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
121 variable timeout = qualifier("timeout", 30);
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
122 variable stale_timeout = qualifier("stale_timeout", 360);
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
123 variable lockfile = filename + ".lock";
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
124 variable tmp_lockfile = lockfile + ".XXXXXX";
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
125 variable time_timeout = _time() + timeout;
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
126 variable time_stale_timeout = _time() - stale_timeout;
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
127
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
128 fd = mkstemp(&tmp_lockfile);
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
129 if (fd == NULL)
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
130 return NULL;
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
131 () = close(fd);
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
132 try {
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
133 % attempt to acquire a lock until time_timeout is reached
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
134 while (_time() < time_timeout) {
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
135 % try to link lockfile to the previously created temporary file,
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
136 % link(2) is atomic even on NFSv2 if the lockfile exists link(2)
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
137 % will fail, this is either detected if EEXIST is returned or the
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
138 % link count of the temporary file is not 2 in this case try to
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
139 % remove a stale lockfile, then wait and try again
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
140 ifnot ((hardlink(tmp_lockfile, lockfile) == 0) ||
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
141 (errno == EEXIST))
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
142 return NULL;
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
143
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
144 st = stat_file(tmp_lockfile);
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
145 if (st == NULL)
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
146 return NULL;
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
147 if (st.st_nlink == 2)
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
148 return lockfile;
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
149
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
150 st = stat_file(lockfile);
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
151 if (st == NULL) {
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
152 ifnot (errno == ENOENT)
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
153 return NULL;
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
154 else
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
155 continue;
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
156 }
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
157
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
158 % remove a stale lockfile after stale_timeout seconds have passed
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
159 if (st.st_mtime < time_stale_timeout)
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
160 () = remove(lockfile);
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
161
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
162 sleep(2);
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
163 }
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
164
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
165 return NULL;
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
166 } finally {
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
167 () = remove(tmp_lockfile);
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
168 }
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
169 }
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
170
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
171 static variable config = struct
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
172 {
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
173 tag_path = ".slrn-tags",
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
174 autosave = 1
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
175 };
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
176
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
177 private variable tag_list = Assoc_Type[Null_Type];
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
178
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
179 private define update_tag_list(ref_tag_list)
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
180 {
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
181 variable new_tag_list = Assoc_Type[Null_Type];
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
182 variable needs_update = 0;
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
183 variable msgid = NULL;
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
184
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
185 call("header_bob");
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
186 % the very first article must be treated specially so it will not be missed
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
187 % when doing next_tagged_header()
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
188 while (((msgid == NULL) && (get_header_flags() & HEADER_TAGGED)) ||
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
189 next_tagged_header()) {
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
190 msgid = extract_article_header("Message-ID");
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
191 if (strlen(msgid) == 0)
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
192 continue;
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
193 new_tag_list[msgid] = NULL;
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
194
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
195 % check if a new element which will go into new_tag_list also exists
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
196 % in tag_list in order to find any difference between both lists
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
197 ifnot (needs_update || assoc_key_exists(@ref_tag_list, msgid))
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
198 needs_update = 1;
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
199 }
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
200
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
201 % if all elements of new_tag_list are also contained in tag_lists
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
202 % check whether all elements of tag_lists are also contained in
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
203 % new_tag_lists in order to find any difference between both lists
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
204 ifnot (needs_update) {
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
205 foreach msgid(@ref_tag_list) using("keys") {
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
206 ifnot (assoc_key_exists(new_tag_list, msgid)) {
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
207 needs_update = 1;
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
208 break;
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
209 }
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
210 }
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
211 }
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
212
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
213 % replace tag_list with new_tag_list
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
214 @ref_tag_list = new_tag_list;
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
215 return needs_update;
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
216 }
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
217
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
218 static define save_tags()
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
219 {
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
220 variable line, fp;
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
221 variable dir = path_concat(make_home_filename(config.tag_path),
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
222 urlencode(server_name()));
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
223 variable filename = path_concat(dir, urlencode(current_newsgroup()));
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
224 variable lockfile;
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
225
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
226 ifnot (update_tag_list(&tag_list))
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
227 return;
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
228
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
229 if (mkdir(dir) == -1) {
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
230 ifnot (errno == EEXIST)
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
231 throw IOError, "mkdir $dir failed: "$ + errno_string(errno);
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
232 }
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
233
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
234 lockfile = lock_file(filename);
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
235 if (lockfile == NULL)
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
236 throw IOError, "failed to lock $filename"$;
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
237
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
238 try {
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
239 % if tag_list is empty remove the file
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
240 if (length(tag_list) == 0) {
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
241 () = remove(filename);
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
242 return;
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
243 }
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
244
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
245 fp = fopen(filename, "w");
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
246 if (fp == NULL)
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
247 throw OpenError, "opening $filename failed: "$ +
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
248 errno_string(errno);
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
249 foreach line(tag_list) using("keys") {
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
250 if (fputs(line + "\n", fp) == -1)
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
251 throw WriteError, "writing to $filename failed: "$ +
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
252 errno_string(errno);
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
253 }
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
254 () = fclose(fp);
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
255 } finally {
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
256 () = remove(lockfile);
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
257 }
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
258 return;
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
259 }
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
260
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
261 static define load_tags()
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
262 {
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
263 variable fp, buf, msgid, pos;
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
264 variable dir = path_concat(make_home_filename(config.tag_path),
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
265 urlencode(server_name()));
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
266 variable filename = path_concat(dir, urlencode(current_newsgroup()));
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
267
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
268 % re-ininitalize tag_list
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
269 tag_list = Assoc_Type[Null_Type];
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
270
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
271 fp = fopen(filename, "r");
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
272 if (fp == NULL) {
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
273 if (errno == ENOENT)
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
274 return;
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
275 throw OpenError, "opening $filename failed: "$ + errno_string(errno);
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
276 }
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
277
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
278 % save position to restore after applying tags
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
279 pos = extract_article_header("Message-ID");
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
280 while (fgets(&buf, fp) != -1) {
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
281 msgid = strtrim(buf);
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
282 if (strlen(msgid)) {
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
283 tag_list[msgid] = NULL;
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
284 if (locate_header_by_msgid(msgid, 1))
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
285 set_header_flags(get_header_flags() | HEADER_TAGGED);
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
286 }
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
287 }
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
288 () = fclose(fp);
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
289 () = locate_header_by_msgid(pos, 0);
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
290
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
291 return;
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
292 }
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
293
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
294 mysrand(_time() * getpid());
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
295
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
296 if (config.autosave)
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
297 {
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
298 () = register_hook("article_mode_hook", "PersistentTags->load_tags");
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
299 () = register_hook("article_mode_quit_hook", "PersistentTags->save_tags");
8eeb70d3d1ce Initial revision
Guido Berhoerster <guido+slrn@berhoerster.name>
parents:
diff changeset
300 }