8192f4dfd8e9b4114124bf4206610c0a5d3874a0
[payproc.git] / src / preorder.c
1 /* preorder.c - Access to the preorder database.
2  * Copyright (C) 2015 g10 Code GmbH
3  *
4  * This file is part of Payproc.
5  *
6  * Payproc is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * Payproc is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, see <http://www.gnu.org/licenses/>.
18  */
19
20 /* The Database used for preorders is pretty simple:  Just a single table:
21
22    CREATE TABLE preorder (
23      ref   TEXT NOT NULL PRIMARY KEY,  -- The "ABCDE" part of ABCDE-NN.
24      refnn INTEGER NOT NULL,           -- The "NN"    part of ABCDE-NN
25      created TEXT NOT NULL,            -- Timestamp
26      paid TEXT,                        -- Timestamp of last payment
27      npaid INTEGER NOT NULL,           -- Total number of payments
28      amount TEXT NOT NULL,             -- with decimal digit; thus TEXT.
29      currency TEXT NOT NULL,
30      desc TEXT,   -- Description of the order
31      email TEXT,  -- Optional mail address.
32      meta TEXT    -- Using the format from the journal.
33    )
34
35
36   Expiring entries can be done using
37
38      DELETE from preorder
39      WHERE julianday(created) < julianday('now', '-30 days')
40            AND paid IS NULL;
41
42   this has not been implemented here but should be done at startup and
43   once a day.  Note that 'paid' tracks actual payments using this ref.
44   We do not delete it from the DB so that the ref can be used for
45   recurring payments.
46
47  */
48
49 #include <config.h>
50
51 #include <stdlib.h>
52 #include <string.h>
53 #include <unistd.h>
54 #include <time.h>
55 #include <npth.h>
56 #include <gcrypt.h>
57 #include <sqlite3.h>
58
59 #include "util.h"
60 #include "logging.h"
61 #include "payprocd.h"
62 #include "journal.h"
63 #include "membuf.h"
64 #include "dbutil.h"
65 #include "preorder.h"
66
67
68
69 /* The name of the preorder database file.  */
70 static const char preorder_db_fname[] = "/var/lib/payproc/preorder.db";
71 static const char preorder_test_db_fname[] = "/var/lib/payproc-test/preorder.db";
72
73 /* The database handle used for the preorder database.  This handle
74    may only used after a successful open_preorder_db call and not
75    after a close_preorder_db call.  The lock variable is maintained by
76    the mentioned open and close functions. */
77 static sqlite3 *preorder_db;
78 static npth_mutex_t preorder_db_lock = NPTH_MUTEX_INITIALIZER;
79
80 /* This is a prepared statement for the INSERT operation.  It is
81    protected by preorder_db_lock.  */
82 static sqlite3_stmt *preorder_insert_stmt;
83
84 /* This is a prepared statement for the UPDATE operation.  It is
85    protected by preorder_db_lock.  */
86 static sqlite3_stmt *preorder_update_stmt;
87
88 /* This is a prepared statement for the SELECT by REF operation.  It
89    is protected by preorder_db_lock.  */
90 static sqlite3_stmt *preorder_select_stmt;
91
92 /* This is a prepared statement for the SELECT by REFNN operation.  It
93    is protected by preorder_db_lock.  */
94 static sqlite3_stmt *preorder_selectrefnn_stmt;
95
96 /* This is a prepared statement for the SELECT all operation.  It
97    is protected by preorder_db_lock.  */
98 static sqlite3_stmt *preorder_selectlist_stmt;
99
100
101
102 \f
103 /* Create a Sepa-Ref field and store it in BUFFER.  The format is:
104
105      AAAAA-NN
106
107   with AAAAA being uppercase letters or digits and NN a value between
108   10 and 99.  Thus the entire length of the returned string is 8.  We
109   use a base 28 alphabet for the A values with the first A restricted
110   to a letter.  Some letters are left out because they might be
111   misrepresented due to OCR scanning.  There are about 11 million
112   different values for AAAAA. */
113 static void
114 make_sepa_ref (char *buffer, size_t bufsize)
115 {
116   static char codes[28] = { 'A', 'B', 'C', 'D', 'E', 'G', 'H', 'J',
117                             'K', 'L', 'N', 'R', 'S', 'T', 'W', 'X',
118                             'Y', 'Z', '0', '1', '2', '3', '4', '5',
119                             '6', '7', '8', '9' };
120   unsigned char nonce[5];
121   int i;
122   unsigned int n;
123
124   if (bufsize < 9)
125     BUG ();
126
127   gcry_create_nonce (nonce, sizeof nonce);
128   buffer[0] = codes[nonce[0] % 18];
129   for (i=1; i < 5; i++)
130     buffer[i] = codes[nonce[i] % 28];
131   buffer[5] = '-';
132   n = (((unsigned int)nonce[0] << 24) | (nonce[1] << 16)
133        | (nonce[2] << 8) | nonce[3]);
134   i = 10 + (n % 90);
135   buffer [6] = '0' + i / 10;
136   buffer [7] = '0' + i % 10;
137   buffer [8] = 0;
138 }
139
140
141 /* Relinquishes the lock on the database handle and if DO_CLOSE is
142    true also close the database handle.  Note that we usually keep the
143    database open for the lifetime of the process.  */
144 static void
145 close_preorder_db (int do_close)
146 {
147   int res;
148
149   if (do_close && preorder_db)
150     {
151       res = sqlite3_close (preorder_db);
152       if (res == SQLITE_BUSY)
153         {
154           sqlite3_finalize (preorder_insert_stmt);
155           preorder_insert_stmt = NULL;
156           sqlite3_finalize (preorder_update_stmt);
157           preorder_update_stmt = NULL;
158           sqlite3_finalize (preorder_select_stmt);
159           preorder_select_stmt = NULL;
160           sqlite3_finalize (preorder_selectrefnn_stmt);
161           preorder_selectrefnn_stmt = NULL;
162           sqlite3_finalize (preorder_selectlist_stmt);
163           preorder_selectlist_stmt = NULL;
164           res = sqlite3_close (preorder_db);
165         }
166       if (res)
167         log_error ("failed to close the preorder db: %s\n",
168                    sqlite3_errstr (res));
169       preorder_db = NULL;
170     }
171
172   res = npth_mutex_unlock (&preorder_db_lock);
173   if (res)
174     log_fatal ("failed to release preorder db lock: %s\n",
175                gpg_strerror (gpg_error_from_errno (res)));
176 }
177
178
179 /* This function opens or creates the preorder database.  If the
180    database is already open it merly takes a lock ion the handle. */
181 static gpg_error_t
182 open_preorder_db (void)
183 {
184   int res;
185   sqlite3_stmt *stmt;
186   const char *db_fname = opt.livemode? preorder_db_fname:preorder_test_db_fname;
187
188   res = npth_mutex_lock (&preorder_db_lock);
189   if (res)
190     log_fatal ("failed to acquire preorder db lock: %s\n",
191                gpg_strerror (gpg_error_from_errno (res)));
192   if (preorder_db)
193     return 0; /* Good: Already open.  */
194
195   /* Database has not yet been opened.  Open or create it, make sure
196      the tables exist, and prepare the required statements.  We use
197      our own locking instead of the more complex serialization sqlite
198      would have to do. */
199
200   res = sqlite3_open_v2 (db_fname,
201                          &preorder_db,
202                          (SQLITE_OPEN_READWRITE
203                           | SQLITE_OPEN_CREATE
204                           | SQLITE_OPEN_NOMUTEX),
205                          NULL);
206   if (res)
207     {
208       log_error ("error opening '%s': %s\n",
209                  db_fname, sqlite3_errstr (res));
210       close_preorder_db (1);
211       return gpg_error (GPG_ERR_GENERAL);
212     }
213   sqlite3_extended_result_codes (preorder_db, 1);
214
215
216   /* Create the tables if needed.  */
217   res = sqlite3_prepare_v2 (preorder_db,
218                             "CREATE TABLE IF NOT EXISTS preorder ("
219                             "ref      TEXT NOT NULL PRIMARY KEY,"
220                             "refnn    INTEGER NOT NULL,"
221                             "created  TEXT NOT NULL,"
222                             "paid TEXT,"
223                             "npaid INTEGER NOT NULL,"
224                             "amount   TEXT NOT NULL,"
225                             "currency TEXT NOT NULL,"
226                             "desc     TEXT,"
227                             "email    TEXT,"
228                             "meta     TEXT,"
229                             "recur    INTEGER"
230                             ")",
231                             -1, &stmt, NULL);
232   if (res)
233     {
234       log_error ("error creating preorder table (prepare): %s\n",
235                  sqlite3_errstr (res));
236       close_preorder_db (1);
237       return gpg_error (GPG_ERR_GENERAL);
238     }
239
240   res = sqlite3_step (stmt);
241   sqlite3_finalize (stmt);
242   if (res != SQLITE_DONE)
243     {
244       log_error ("error creating preorder table: %s\n", sqlite3_errstr (res));
245       close_preorder_db (1);
246       return gpg_error (GPG_ERR_GENERAL);
247     }
248
249   /* Add the new column recur to the table.  */
250   res = sqlite3_prepare_v2 (preorder_db,
251                             "ALTER TABLE preorder ADD COLUMN \n"
252                             "recur INTEGER",
253                             -1, &stmt, NULL);
254   if (!res)
255     {
256       res = sqlite3_step (stmt);
257       sqlite3_finalize (stmt);
258       if (res != SQLITE_DONE)
259         {
260           log_error ("error adding column to preorder table: %s\n",
261                      sqlite3_errstr (res));
262           close_preorder_db (1);
263           return gpg_error (GPG_ERR_GENERAL);
264         }
265     }
266
267
268   /* Prepare an insert statement.  */
269   res = sqlite3_prepare_v2 (preorder_db,
270                             "INSERT INTO preorder VALUES ("
271                             "?1,?2,?3,NULL,0,?4,?5,?6,?7,?8,?9"
272                             ")",
273                             -1, &stmt, NULL);
274   if (res)
275     {
276       log_error ("error preparing insert statement: %s\n",
277                  sqlite3_errstr (res));
278       close_preorder_db (1);
279       return gpg_error (GPG_ERR_GENERAL);
280     }
281   preorder_insert_stmt = stmt;
282
283   /* Prepare an update statement.  */
284   res = sqlite3_prepare_v2 (preorder_db,
285                             "UPDATE preorder SET"
286                             " paid = ?2,"
287                             " npaid = npaid + 1"
288                             " WHERE ref=?1",
289                             -1, &stmt, NULL);
290   if (res)
291     {
292       log_error ("error preparing update statement: %s\n",
293                  sqlite3_errstr (res));
294       close_preorder_db (1);
295       return gpg_error (GPG_ERR_GENERAL);
296     }
297   preorder_update_stmt = stmt;
298
299   /* Prepare a select statement.  */
300   res = sqlite3_prepare_v2 (preorder_db,
301                             "SELECT * FROM preorder WHERE ref=?1",
302                             -1, &stmt, NULL);
303   if (res)
304     {
305       log_error ("error preparing select statement: %s\n",
306                  sqlite3_errstr (res));
307       close_preorder_db (1);
308       return gpg_error (GPG_ERR_GENERAL);
309     }
310   preorder_select_stmt = stmt;
311
312   /* Prepare a select-refnn statement.  */
313   res = sqlite3_prepare_v2 (preorder_db,
314                             "SELECT * FROM preorder "
315                             "WHERE refnn=?1 ORDER BY ref",
316                             -1, &stmt, NULL);
317   if (res)
318     {
319       log_error ("error preparing selectrefnn statement: %s\n",
320                  sqlite3_errstr (res));
321       close_preorder_db (1);
322       return gpg_error (GPG_ERR_GENERAL);
323     }
324   preorder_selectrefnn_stmt = stmt;
325
326   /* Prepare a select-list statement.  */
327   res = sqlite3_prepare_v2 (preorder_db,
328                             "SELECT * FROM preorder "
329                             "ORDER BY created DESC, refnn ASC",
330                             -1, &stmt, NULL);
331   if (res)
332     {
333       log_error ("error preparing select statement: %s\n",
334                  sqlite3_errstr (res));
335       close_preorder_db (1);
336       return gpg_error (GPG_ERR_GENERAL);
337     }
338   preorder_selectlist_stmt = stmt;
339
340   return 0;
341 }
342
343
344 /* Insert a record into the preorder table.  The values are taken from
345    the dictionary at DICTP.  On return a Sepa-Ref value will have been
346    inserted into it; that may happen even on error.  */
347 static gpg_error_t
348 insert_preorder_record (keyvalue_t *dictp)
349 {
350   gpg_error_t err;
351   int res;
352   keyvalue_t dict = *dictp;
353   char separef[9];
354   char *buf;
355   char datetime_buf [DB_DATETIME_SIZE];
356   int retrycount = 0;
357
358  retry:
359   make_sepa_ref (separef, sizeof separef);
360   err = keyvalue_put (dictp, "Sepa-Ref", separef);
361   if (err)
362     return err;
363   dict = *dictp;
364
365   sqlite3_reset (preorder_insert_stmt);
366
367   separef[5] = 0;
368   res = sqlite3_bind_text (preorder_insert_stmt,
369                            1, separef, -1, SQLITE_TRANSIENT);
370   if (!res)
371     res = sqlite3_bind_int (preorder_insert_stmt,
372                             2, atoi (separef + 6));
373   if (!res)
374     res = sqlite3_bind_text (preorder_insert_stmt,
375                              3, db_datetime_now (datetime_buf),
376                              -1, SQLITE_TRANSIENT);
377   if (!res)
378     res = sqlite3_bind_text (preorder_insert_stmt,
379                              4, keyvalue_get_string (dict, "Amount"),
380                              -1, SQLITE_TRANSIENT);
381   if (!res)
382     res = sqlite3_bind_text (preorder_insert_stmt,
383                              5, "EUR", -1, SQLITE_STATIC);
384   if (!res)
385     res = sqlite3_bind_text (preorder_insert_stmt,
386                              6, keyvalue_get (dict, "Desc"),
387                              -1, SQLITE_TRANSIENT);
388   if (!res)
389     res = sqlite3_bind_text (preorder_insert_stmt,
390                              7, keyvalue_get (dict, "Email"),
391                              -1, SQLITE_TRANSIENT);
392   if (!res)
393     {
394       buf = meta_field_to_string (dict);
395       if (!buf)
396         res = sqlite3_bind_null (preorder_insert_stmt, 8);
397       else
398         res = sqlite3_bind_text (preorder_insert_stmt, 8, buf, -1, es_free);
399     }
400   if (!res)
401     res = sqlite3_bind_int (preorder_insert_stmt,
402                             9, atoi (keyvalue_get_string (dict, "Recur")));
403
404   if (res)
405     {
406       log_error ("error binding a value for the preorder table: %s\n",
407                  sqlite3_errstr (res));
408       return gpg_error (GPG_ERR_GENERAL);
409     }
410
411   res = sqlite3_step (preorder_insert_stmt);
412   if (res == SQLITE_DONE)
413     return 0;
414
415   /* In case we hit the same primary key we need to retry.  This is
416      limited to 11000 retries (~0.1% of the primary key space).  */
417   if (res == SQLITE_CONSTRAINT_PRIMARYKEY && ++retrycount < 11000)
418     goto retry;
419
420   log_error ("error inserting into preorder table: %s (%d)\n",
421              sqlite3_errstr (res), res);
422   return gpg_error (GPG_ERR_GENERAL);
423 }
424
425
426 static gpg_error_t
427 get_text_column (sqlite3_stmt *stmt, int idx, int icol, const char *name,
428                  keyvalue_t *dictp)
429 {
430   gpg_error_t err;
431   const char *s;
432
433   s = sqlite3_column_text (stmt, icol);
434   if (!s && sqlite3_errcode (preorder_db) == SQLITE_NOMEM)
435     err = gpg_error (GPG_ERR_ENOMEM);
436   else if (!strcmp (name, "Meta"))
437     err = s? keyvalue_put_meta (dictp, s) : 0;
438   else
439     err = keyvalue_put_idx (dictp, name, idx, s);
440
441   return err;
442 }
443
444
445 /* Put all columns into DICTP.  */
446 static gpg_error_t
447 get_columns (sqlite3_stmt *stmt, int idx, keyvalue_t *dictp)
448 {
449   gpg_error_t err;
450   char separef[9];
451   const char *s;
452   int i;
453
454   s = sqlite3_column_text (stmt, 0);
455   if (!s && sqlite3_errcode (preorder_db) == SQLITE_NOMEM)
456     err = gpg_error (GPG_ERR_ENOMEM);
457   else
458     {
459       strncpy (separef, s, 5);
460       i = sqlite3_column_int (stmt, 1);
461       if (!i && sqlite3_errcode (preorder_db) == SQLITE_NOMEM)
462         err = gpg_error (GPG_ERR_ENOMEM);
463       else if (i < 0 || i > 99)
464         err = gpg_error (GPG_ERR_INV_DATA);
465       else
466         {
467           snprintf (separef+5, 4, "-%02d", i);
468           err = keyvalue_put_idx (dictp, "Sepa-Ref", idx, separef);
469         }
470     }
471
472   if (!err)
473     err = get_text_column (stmt, idx, 2, "Created", dictp);
474   if (!err)
475     err = get_text_column (stmt, idx, 3, "Paid", dictp);
476   if (!err)
477     err = get_text_column (stmt, idx, 4, "N-Paid", dictp);
478   if (!err)
479     err = get_text_column (stmt, idx, 5, "Amount", dictp);
480   if (!err)
481     err = get_text_column (stmt, idx, 6, "Currency", dictp);
482   if (!err)
483     err = get_text_column (stmt, idx, 7, "Desc", dictp);
484   if (!err)
485     err = get_text_column (stmt, idx, 8, "Email", dictp);
486   if (!err)
487     err = get_text_column (stmt, idx, 9, "Meta", dictp);
488   if (!err)
489     err = get_text_column (stmt, idx, 10, "Recur", dictp);
490
491   return err;
492 }
493
494
495 /* Format columns and put the formatted line into DICTP under the
496    key "D[idx]".  */
497 static gpg_error_t
498 format_columns (sqlite3_stmt *stmt, int idx, keyvalue_t *dictp)
499 {
500   gpg_error_t err;
501   membuf_t mb;
502   const char *s;
503   int i;
504
505   init_membuf (&mb, 512);
506
507   s = sqlite3_column_text (stmt, 0);
508   if (!s && sqlite3_errcode (preorder_db) == SQLITE_NOMEM)
509     {
510       err = gpg_error (GPG_ERR_ENOMEM);
511       goto leave;
512     }
513
514   i = sqlite3_column_int (stmt, 1);
515   if (!i && sqlite3_errcode (preorder_db) == SQLITE_NOMEM)
516     {
517       err = gpg_error (GPG_ERR_ENOMEM);
518       goto leave;
519     }
520   put_membuf_printf (&mb, "|%s-%02d", s, i);
521
522   for (i = 2; i <= 9; i++)
523     {
524       put_membuf_chr (&mb, '|');
525       s = sqlite3_column_text (stmt, i);
526       if (!s && sqlite3_errcode (preorder_db) == SQLITE_NOMEM)
527         {
528           err = gpg_error (GPG_ERR_ENOMEM);
529           goto leave;
530         }
531       if (!s)
532         ;
533       else if (strchr (s, '|'))
534         {
535           for (; *s; s++)
536             if (*s == '|')
537               put_membuf_str (&mb, "=7C");
538             else
539               put_membuf_chr (&mb, *s);
540         }
541       else
542         put_membuf_str (&mb, s);
543     }
544
545   i = sqlite3_column_int (stmt, 10);
546   if (!i && sqlite3_errcode (preorder_db) == SQLITE_NOMEM)
547     {
548       err = gpg_error (GPG_ERR_ENOMEM);
549       goto leave;
550     }
551   put_membuf_printf (&mb, "|%d", i);
552
553   put_membuf_chr (&mb, '|');
554
555
556   {
557     char *p;
558
559     put_membuf_chr (&mb, 0);
560     p = get_membuf (&mb, NULL);
561     if (!p)
562       err = gpg_error_from_syserror ();
563     else
564       {
565         err = keyvalue_put_idx (dictp, "D", idx, p);
566         xfree (p);
567       }
568   }
569
570  leave:
571   xfree (get_membuf (&mb, NULL));
572   return err;
573 }
574
575
576 /* Get a record from the preorder table.  The values are stored at the
577    dictionary at DICTP.  */
578 static gpg_error_t
579 get_preorder_record (const char *ref, keyvalue_t *dictp)
580 {
581   gpg_error_t err;
582   int res;
583
584   if (strlen (ref) != 5)
585     return gpg_error (GPG_ERR_INV_LENGTH);
586
587   sqlite3_reset (preorder_select_stmt);
588
589   res = sqlite3_bind_text (preorder_select_stmt,
590                            1, ref, 5, SQLITE_TRANSIENT);
591   if (res)
592     {
593       log_error ("error binding a value for the preorder table: %s\n",
594                  sqlite3_errstr (res));
595       return gpg_error (GPG_ERR_GENERAL);
596     }
597
598   res = sqlite3_step (preorder_select_stmt);
599   if (res == SQLITE_ROW)
600     {
601       res = SQLITE_OK;
602       err = get_columns (preorder_select_stmt, -1, dictp);
603     }
604   else if (res == SQLITE_DONE)
605     {
606       res = SQLITE_OK;
607       err = gpg_error (GPG_ERR_NOT_FOUND);
608     }
609   else
610     err = gpg_error (GPG_ERR_GENERAL);
611
612   if (err)
613     {
614       if (res == SQLITE_OK)
615         log_error ("error selecting from preorder table: %s\n",
616                    gpg_strerror (err));
617       else
618         log_error ("error selecting from preorder table: %s [%s (%d)]\n",
619                    gpg_strerror (err), sqlite3_errstr (res), res);
620     }
621   return err;
622 }
623
624
625 /* List records from the preorder table.  The values are stored at the
626    dictionary at DICTP with a D[n] key.  The number of records is
627    stored at R_COUNT.  */
628 static gpg_error_t
629 list_preorder_records (const char *refnn,
630                        keyvalue_t *dictp, unsigned int *r_count)
631 {
632   gpg_error_t err;
633   sqlite3_stmt *stmt;
634   int count = 0;
635   int res;
636
637   stmt = *refnn? preorder_selectrefnn_stmt : preorder_selectlist_stmt;
638
639   sqlite3_reset (stmt);
640
641   if (*refnn)
642     {
643       res = sqlite3_bind_text (stmt, 1, refnn, -1, SQLITE_TRANSIENT);
644       if (res)
645         {
646           log_error ("error binding a value for the preorder table: %s\n",
647                      sqlite3_errstr (res));
648           return gpg_error (GPG_ERR_GENERAL);
649         }
650     }
651
652  next:
653   res = sqlite3_step (stmt);
654   if (res == SQLITE_ROW)
655     {
656       res = SQLITE_OK;
657       err = format_columns (stmt, count, dictp);
658       if (!err)
659         {
660           if (++count)
661             goto next;
662           err = gpg_error (GPG_ERR_WOULD_WRAP);
663         }
664     }
665   else if (res == SQLITE_DONE)
666     {
667       res = SQLITE_OK;
668       err = 0;
669     }
670   else
671     err = gpg_error (GPG_ERR_GENERAL);
672
673   if (err)
674     {
675       if (res == SQLITE_OK)
676         log_error ("error selecting from preorder table: %s\n",
677                    gpg_strerror (err));
678       else
679         log_error ("error selecting from preorder table: %s [%s (%d)]\n",
680                    gpg_strerror (err), sqlite3_errstr (res), res);
681     }
682   else
683     *r_count = count;
684   return err;
685 }
686
687
688 /* Update a row specified by REF in the preorder table.  Also update
689    the timestamp field at DICTP. */
690 static gpg_error_t
691 update_preorder_record (const char *ref, keyvalue_t *dictp)
692 {
693   gpg_error_t err;
694   int res;
695   char datetime_buf [DB_DATETIME_SIZE];
696
697   if (strlen (ref) != 5)
698     return gpg_error (GPG_ERR_INV_LENGTH);
699
700   sqlite3_reset (preorder_update_stmt);
701
702   res = sqlite3_bind_text (preorder_update_stmt,
703                            1, ref, 5,
704                            SQLITE_TRANSIENT);
705   if (!res)
706     res = sqlite3_bind_text (preorder_update_stmt,
707                              2, db_datetime_now (datetime_buf), -1,
708                              SQLITE_TRANSIENT);
709   if (res)
710     {
711       log_error ("error binding a value for the preorder table: %s\n",
712                  sqlite3_errstr (res));
713       return gpg_error (GPG_ERR_GENERAL);
714     }
715
716   res = sqlite3_step (preorder_update_stmt);
717   if (res == SQLITE_DONE)
718     {
719       if (!sqlite3_changes (preorder_db))
720         err = gpg_error (GPG_ERR_NOT_FOUND);
721       else
722         err = 0;
723     }
724   else
725     err = gpg_error (GPG_ERR_GENERAL);
726
727   if (!err)
728     err = keyvalue_put (dictp, "_timestamp", datetime_buf);
729
730   if (gpg_err_code (err) == GPG_ERR_GENERAL)
731     log_error ("error updating preorder table: %s [%s (%d)]\n",
732                gpg_strerror (err), sqlite3_errstr (res), res);
733   else
734     log_error ("error updating preorder table: %s\n",
735                gpg_strerror (err));
736   return err;
737 }
738
739
740 /* Create a new preorder record and store it.  Inserts a "Sepa-Ref"
741    into DICT.  */
742 gpg_error_t
743 preorder_store_record (keyvalue_t *dictp)
744 {
745   gpg_error_t err;
746
747   err = open_preorder_db ();
748   if (err)
749     return err;
750
751   err = insert_preorder_record (dictp);
752   close_preorder_db (0);
753
754   return err;
755 }
756
757
758 /* Take the Sepa-Ref from DICTP, fetch the row, and update DICTP with
759    that data.  On error return an error code.  Note that DICTP may
760    even be changed on error.  */
761 gpg_error_t
762 preorder_get_record (keyvalue_t *dictp)
763 {
764   gpg_error_t err;
765   char separef[9];
766   const char *s;
767   char *p;
768
769   s = keyvalue_get (*dictp, "Sepa-Ref");
770   if (!s || strlen (s) >= sizeof separef)
771     return gpg_error (GPG_ERR_INV_LENGTH);
772   strcpy (separef, s);
773   p = strchr (separef, '-');
774   if (p)
775     *p = 0;
776
777   err = open_preorder_db ();
778   if (err)
779     return err;
780
781   err = get_preorder_record (separef, dictp);
782
783   close_preorder_db (0);
784
785   return err;
786 }
787
788
789 /* Take the number Sepa-Ref from DICTP, fetch the row, and update DICTP with
790    that data.  On error return an error code.  Note that DICTP may
791    even be changed on error.  */
792 gpg_error_t
793 preorder_list_records (keyvalue_t *dictp, unsigned int *r_count)
794 {
795   gpg_error_t err;
796   char refnn[3];
797   const char *s;
798
799   *r_count = 0;
800   s = keyvalue_get (*dictp, "Refnn");
801   if (s)
802     {
803       if (strlen (s) != 2)
804         return gpg_error (GPG_ERR_INV_LENGTH);
805       strcpy (refnn, s);
806     }
807   else
808     *refnn = 0;
809
810   err = open_preorder_db ();
811   if (err)
812     return err;
813
814   err = list_preorder_records (refnn, dictp, r_count);
815
816   close_preorder_db (0);
817
818   return err;
819 }
820
821
822 /* Take the Sepa-Ref from NEWDATA and update the corresponding row with
823    the other data from NEWDATA.  On error return an error code.  */
824 gpg_error_t
825 preorder_update_record (keyvalue_t newdata)
826 {
827   gpg_error_t err;
828   char separef[9];
829   const char *s;
830   char *p;
831   keyvalue_t olddata = NULL;
832
833   s = keyvalue_get (newdata, "Sepa-Ref");
834   if (!s || strlen (s) >= sizeof separef)
835     return gpg_error (GPG_ERR_INV_LENGTH);
836   strcpy (separef, s);
837   p = strchr (separef, '-');
838   if (p)
839     *p = 0;
840
841   err = open_preorder_db ();
842   if (err)
843     return err;
844
845   err = get_preorder_record (separef, &olddata);
846   if (err)
847     goto leave;
848
849   /* Update OLDDATA with the actual amount so that we can put the
850      correct amount into the log.  */
851   err = keyvalue_put (&olddata, "Amount",
852                       keyvalue_get_string (newdata, "Amount"));
853   if (err)
854     goto leave;
855
856   /* We pass OLDDATA so that _timestamp will be set.  */
857   err = update_preorder_record (separef, &olddata);
858   if (err)
859     goto leave;
860
861   /* FIXME: Unfortunately the journal function creates its own
862      timestamp.  */
863   jrnl_store_charge_record (&olddata, PAYMENT_SERVICE_SEPA, 0);
864
865
866  leave:
867   close_preorder_db (0);
868   keyvalue_release (olddata);
869
870   return err;
871 }