2 * coded by Ketmar // Invisible Vector <ketmar@ketmar.no-ip.org>
3 * Understanding is not required. Only obedience.
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, version 3 of the License ONLY.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 // WARNING! this doesn't perform any sanity checks on "accounts.rc"!
18 module zsq_create_twits
is aliced
;
31 // ////////////////////////////////////////////////////////////////////////// //
32 void main (string
[] args
) {
33 ChiroTimerEnabled
= true;
34 chiroParseCommonCLIArgs(args
);
36 // here, i don't have any threads at all
37 if (sqlite3_config(SQLITE_CONFIG_SINGLETHREAD
) != SQLITE_OK
) throw new Exception("cannot switch SQLite to multi-threaded mode");
40 foreach (string s
; args
[1..$]) {
41 if (s
== "force") allowed
= true;
43 if (!allowed
) throw new Exception("use \"force\" to rebuild");
47 // we will re-import them
49 DELETE FROM emailtwits;
50 DELETE FROM msgidtwits;
53 auto stInsTwitEMail
= dbConf
.persistentStatement(`
54 INSERT INTO emailtwits
55 ( tagglob, email, name, title, notes)
56 VALUES(:tagglob,:email,:name,:title,:notes)
59 auto stInsTwitMsgid
= dbConf
.persistentStatement(`
60 INSERT INTO msgidtwits
61 ( etwitid, tagglob, msgid, automatic)
62 VALUES(:etwitid,:tagglob,:msgid, 0)
65 uint hasTwitEMail (const(char)[] email
, const(char)[] name
) {
66 if (name
.length
== 0) {
67 if (email
.length
== 0) return 0;
69 foreach (auto row
; dbConf
.statement(`SELECT rowid AS twitid FROM emailtwits WHERE email=:email;`).bindConstText(":email", email
).range
) return row
.twitid
!uint;
70 } else if (email
.length
== 0) {
72 foreach (auto row
; dbConf
.statement(`SELECT rowid AS twitid FROM emailtwits WHERE name=:name;`).bindConstText(":name", name
).range
) return row
.twitid
!uint;
74 // both name and email
75 foreach (auto row
; dbConf
.statement(`SELECT rowid AS twitid FROM emailtwits WHERE email=:email AND name=:name;`)
76 .bindConstText(":email", email
).bindConstText(":name", name
).range
) return row
.twitid
!uint;
82 bool hasTwitMsgid (const(char)[] msgid) {
83 if (msgid.length == 0) return false;
84 foreach (auto row; dbConf.statement(`SELECT rowid FROM msgidtwits WHERE msgid=:msgid;`).bindConstText(":msgid", msgid).range) return true;
89 dbConf
.execute("BEGIN TRANSACTION;");
90 scope(failure
) dbConf
.execute("ROLLBACK TRANSACTION;");
92 void insertTwit (string
[] argv
) {
93 string tagglob
= null;
98 string notes
= null; /* url */
100 if (argv
[0] != "twit_set" && argv
[0] != "twit_thread") throw new Exception("expected \"twit_set\", but got \""~argv
[0]~"\"");
101 if (argv
.length
< 2) throw new Exception("\"twit_set\" don't have any arguments");
103 for (usize aidx
= 1; aidx
< argv
.length
; ) {
104 string aname
= argv
[aidx
++];
108 if (tagglob
!is null) throw new Exception("duplicate tag glob, old is \""~tagglob
~"\", new is \""~argv
[aidx
+1]~"\"");
109 tagglob
= argv
[aidx
++];
110 if (tagglob
.length
&& tagglob
[0].isalpha()) tagglob
= "/"~tagglob
;
116 if (msgid
!is null) throw new Exception("duplicate message id, old is \""~msgid
~"\", new is \""~argv
[aidx
+1]~"\"");
117 msgid
= argv
[aidx
++];
118 if (msgid
.length
>= 2 && msgid
[0] == '<' && msgid
[$-1] == '>') msgid
= msgid
[1..$-1].xstrip
;
123 if (email
!is null) throw new Exception("duplicate email, old is \""~email
~"\", new is \""~argv
[aidx
+1]~"\"");
124 email
= argv
[aidx
++].toLowerStr
;
125 if (!isGoodEmail(email
) && email
.indexOf('*') < 0) throw new Exception("invalid email \""~email
~"\"");
128 if (name
!is null) throw new Exception("duplicate name, old is \""~name
~"\", new is \""~argv
[aidx
+1]~"\"");
132 if (title
!is null) throw new Exception("duplicate title, old is \""~title
~"\", new is \""~argv
[aidx
+1]~"\"");
133 title
= argv
[aidx
++];
137 if (notes
!is null) throw new Exception("duplicate notes, old is \""~notes
~"\", new is \""~argv
[aidx
+1]~"\"");
138 notes
= argv
[aidx
++];
141 throw new Exception("unknown option \""~aname
~"\"");
145 while (tagglob
.length
&& tagglob
[$-1] == '/') tagglob
= tagglob
[0..$-1];
146 if (tagglob
.length
&& isalnum(tagglob
[0])) tagglob
= "/"~tagglob
;
148 if (tagglob
.length
== 0) throw new Exception("missing tag glob");
149 if (email
.length
== 0 && name
.length
== 0 && msgid
.length
== 0) {
150 throw new Exception("missing email, name or msgid");
153 uint etid
= hasTwitEMail(email
, name
);
155 if (hasTwitEMail(email, name)) {
156 writeln("duplicate twit for: email=\"", email, "\"; name=\"", name, "\"");
159 if (email
.length || name
.length
) {
161 .bindConstText(":tagglob", tagglob
)
162 .bindConstText(":email", email
)
163 .bindConstText(":name", name
)
164 .bindConstText(":title", title
, allowNull
:true)
165 .bindConstText(":notes", notes
, allowNull
:true)
167 etid
= cast(uint)dbConf
.lastRowId
;
172 .bind(":etwitid", etid
)
173 .bindConstText(":tagglob", tagglob
)
174 .bindConstText(":msgid", msgid
, allowNull
:true)
180 foreach (string
[] argv
; loadRCFile("twits.rc")) { insertTwit(argv
); ++count
; }
181 foreach (string
[] argv
; loadRCFile("twit_threads.rc")) { insertTwit(argv
); ++count
; }
182 foreach (string
[] argv
; loadRCFile("auto_twits.rc")) { insertTwit(argv
); ++count
; }
183 foreach (string
[] argv
; loadRCFile("auto_twit_threads.rc")) { insertTwit(argv
); ++count
; }
184 dbConf
.execute("COMMIT TRANSACTION;");
186 writeln(count
, " twit entries added.");
188 writeln("closing the db");
189 dbConf
.execute("ANALYZE;");