]> git.stg.codes - stg.git/blob - stargazer/plugins/store/postgresql/postgresql_store_users.cpp
Fix funtests to work with the new build system.
[stg.git] / stargazer / plugins / store / postgresql / postgresql_store_users.cpp
1 /*
2  *    This program is free software; you can redistribute it and/or modify
3  *    it under the terms of the GNU General Public License as published by
4  *    the Free Software Foundation; either version 2 of the License, or
5  *    (at your option) any later version.
6  *
7  *    This program is distributed in the hope that it will be useful,
8  *    but WITHOUT ANY WARRANTY; without even the implied warranty of
9  *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  *    GNU General Public License for more details.
11  *
12  *    You should have received a copy of the GNU General Public License
13  *    along with this program; if not, write to the Free Software
14  *    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
15  */
16
17 /*
18  *    Author : Maxim Mamontov <faust@stargazer.dp.ua>
19  */
20
21 /*
22  *  User manipulation methods
23  *
24  *  $Revision: 1.14 $
25  *  $Date: 2010/05/07 07:26:36 $
26  *
27  */
28
29 #include <string>
30 #include <vector>
31 #include <sstream>
32 #include <ctime>
33
34 #include <libpq-fe.h>
35
36 #include "stg/common.h"
37 #include "stg/const.h"
38 #include "stg/locker.h"
39 #include "../../../stg_timer.h"
40 #include "postgresql_store.h"
41
42 //-----------------------------------------------------------------------------
43 int POSTGRESQL_STORE::GetUsersList(std::vector<std::string> * usersList) const
44 {
45 STG_LOCKER lock(&mutex);
46
47 if (PQstatus(connection) != CONNECTION_OK)
48     {
49     printfd(__FILE__, "POSTGRESQL_STORE::GetUsersList(): 'Connection lost. Trying to reconnect...'\n", strError.c_str());
50     if (Reset())
51         {
52         strError = "Connection lost";
53         printfd(__FILE__, "POSTGRESQL_STORE::GetUsersList(): '%s'\n", strError.c_str());
54         return -1;
55         }
56     }
57
58 PGresult * result;
59
60 if (StartTransaction())
61     {
62     printfd(__FILE__, "POSTGRESQL_STORE::GetUsersList(): 'Failed to start transaction'\n");
63     return -1;
64     }
65
66 result = PQexec(connection, "SELECT name FROM tb_users");
67
68 if (PQresultStatus(result) != PGRES_TUPLES_OK)
69     {
70     strError = PQresultErrorMessage(result);
71     PQclear(result);
72     printfd(__FILE__, "POSTGRESQL_STORE::GetUsersList(): '%s'\n", strError.c_str());
73     if (RollbackTransaction())
74         {
75         printfd(__FILE__, "POSTGRESQL_STORE::GetUsersList(): 'Failed to rollback transaction'\n");
76         }
77     return -1;
78     }
79
80 int tuples = PQntuples(result);
81
82 for (int i = 0; i < tuples; ++i)
83     {
84     usersList->push_back(PQgetvalue(result, i, 0));
85     }
86
87 PQclear(result);
88
89 if (CommitTransaction())
90     {
91     printfd(__FILE__, "POSTGRESQL_STORE::GetUsersList(): 'Failed to commit transaction'\n");
92     return -1;
93     }
94
95 return 0;
96 }
97
98 //-----------------------------------------------------------------------------
99 int POSTGRESQL_STORE::AddUser(const std::string & name) const
100 {
101 STG_LOCKER lock(&mutex);
102
103 if (PQstatus(connection) != CONNECTION_OK)
104     {
105     printfd(__FILE__, "POSTGRESQL_STORE::AddUser(): 'Connection lost. Trying to reconnect...'\n", strError.c_str());
106     if (Reset())
107         {
108         strError = "Connection lost";
109         printfd(__FILE__, "POSTGRESQL_STORE::AddUser(): '%s'\n", strError.c_str());
110         return -1;
111         }
112     }
113
114 PGresult * result;
115
116 if (StartTransaction())
117     {
118     printfd(__FILE__, "POSTGRESQL_STORE::AddUser(): 'Failed to start transaction'\n");
119     return -1;
120     }
121
122 std::string elogin = name;
123
124 if (EscapeString(elogin))
125     {
126     printfd(__FILE__, "POSTGRESQL_STORE::AddUser(): 'Failed to escape login'\n");
127     if (RollbackTransaction())
128         {
129         printfd(__FILE__, "POSTGRESQL_STORE::AddUser(): 'Failed to rollback transaction'\n");
130         }
131     return -1;
132     }
133
134 std::ostringstream query;
135 query << "SELECT sp_add_user('" << elogin << "')";
136
137 result = PQexec(connection, query.str().c_str());
138
139 if (PQresultStatus(result) != PGRES_TUPLES_OK)
140     {
141     strError = PQresultErrorMessage(result);
142     PQclear(result);
143     printfd(__FILE__, "POSTGRESQL_STORE::AddUser(): '%s'\n", strError.c_str());
144     if (RollbackTransaction())
145         {
146         printfd(__FILE__, "POSTGRESQL_STORE::AddUser(): 'Failed to rollback transaction'\n");
147         }
148     return -1;
149     }
150
151 PQclear(result);
152
153 if (CommitTransaction())
154     {
155     printfd(__FILE__, "POSTGRESQL_STORE::AddUser(): 'Failed to commit transaction'\n");
156     return -1;
157     }
158
159 return 0;
160 }
161
162 //-----------------------------------------------------------------------------
163 int POSTGRESQL_STORE::DelUser(const std::string & login) const
164 {
165 STG_LOCKER lock(&mutex);
166
167 if (PQstatus(connection) != CONNECTION_OK)
168     {
169     printfd(__FILE__, "POSTGRESQL_STORE::DelUser(): 'Connection lost. Trying to reconnect...'\n", strError.c_str());
170     if (Reset())
171         {
172         strError = "Connection lost";
173         printfd(__FILE__, "POSTGRESQL_STORE::DelUser(): '%s'\n", strError.c_str());
174         return -1;
175         }
176     }
177
178 PGresult * result;
179
180 if (StartTransaction())
181     {
182     printfd(__FILE__, "POSTGRESQL_STORE::DelUser(): 'Failed to start transaction'\n");
183     return -1;
184     }
185
186 std::string elogin = login;
187
188 if (EscapeString(elogin))
189     {
190     printfd(__FILE__, "POSTGRESQL_STORE::DelUser(): 'Failed to escape login'\n");
191     if (RollbackTransaction())
192         {
193         printfd(__FILE__, "POSTGRESQL_STORE::DelUser(): 'Failed to rollback transaction'\n");
194         }
195     return -1;
196     }
197
198 std::ostringstream query;
199 query << "DELETE FROM tb_users WHERE name = '" << elogin << "'";
200
201 result = PQexec(connection, query.str().c_str());
202
203 if (PQresultStatus(result) != PGRES_COMMAND_OK)
204     {
205     strError = PQresultErrorMessage(result);
206     PQclear(result);
207     printfd(__FILE__, "POSTGRESQL_STORE::DelUser(): '%s'\n", strError.c_str());
208     if (RollbackTransaction())
209         {
210         printfd(__FILE__, "POSTGRESQL_STORE::DelUser(): 'Failed to rollback transaction'\n");
211         }
212     return -1;
213     }
214
215 PQclear(result);
216
217 if (CommitTransaction())
218     {
219     printfd(__FILE__, "POSTGRESQL_STORE::DelUser(): 'Failed to commit transaction'\n");
220     return -1;
221     }
222
223 return 0;
224 }
225 //-----------------------------------------------------------------------------
226 int POSTGRESQL_STORE::SaveUserStat(const USER_STAT & stat,
227                                    const std::string & login) const
228 {
229 STG_LOCKER lock(&mutex);
230
231 return SaveStat(stat, login);
232 }
233 //-----------------------------------------------------------------------------
234 int POSTGRESQL_STORE::SaveStat(const USER_STAT & stat,
235                                const std::string & login,
236                                int year,
237                                int month) const
238 {
239 if (PQstatus(connection) != CONNECTION_OK)
240     {
241     printfd(__FILE__, "POSTGRESQL_STORE::SaveStat(): 'Connection lost. Trying to reconnect...'\n", strError.c_str());
242     if (Reset())
243         {
244         strError = "Connection lost";
245         printfd(__FILE__, "POSTGRESQL_STORE::SaveStat(): '%s'\n", strError.c_str());
246         return -1;
247         }
248     }
249
250 PGresult * result;
251
252 if (StartTransaction())
253     {
254     printfd(__FILE__, "POSTGRESQL_STORE::SaveStat(): 'Failed to start transaction'\n");
255     return -1;
256     }
257
258 std::string elogin = login;
259
260 if (EscapeString(elogin))
261     {
262     printfd(__FILE__, "POSTGRESQL_STORE::SaveStat(): 'Failed to escape login'\n");
263     if (RollbackTransaction())
264         {
265         printfd(__FILE__, "POSTGRESQL_STORE::SaveStat(): 'Failed to rollback transaction'\n");
266         }
267     return -1;
268     }
269
270 std::ostringstream query;
271 query << "UPDATE tb_users SET "
272             "cash = " << stat.cash << ", "
273             "free_mb = " << stat.freeMb << ", "
274             "last_activity_time = CAST('" << formatTime(stat.lastActivityTime) << "' AS TIMESTAMP), "
275             "last_cash_add = " << stat.lastCashAdd << ", "
276             "last_cash_add_time = CAST('" << formatTime(stat.lastCashAddTime) << "' AS TIMESTAMP), "
277             "passive_time = " << stat.passiveTime << " "
278          "WHERE name = '" << elogin << "'";
279
280 result = PQexec(connection, query.str().c_str());
281
282 if (PQresultStatus(result) != PGRES_COMMAND_OK)
283     {
284     strError = PQresultErrorMessage(result);
285     PQclear(result);
286     printfd(__FILE__, "POSTGRESQL_STORE::SaveStat(): '%s'\n", strError.c_str());
287     if (RollbackTransaction())
288         {
289         printfd(__FILE__, "POSTGRESQL_STORE::SaveStat(): 'Failed to rollback transaction'\n");
290         }
291     return -1;
292     }
293
294 PQclear(result);
295
296 std::string date;
297
298 MakeDate(date, year, month);
299
300 for (int dir = 0; dir < DIR_NUM; ++dir)
301     {
302     query.str("");
303     query << "SELECT sp_add_stats_traffic ("
304                 "'" << elogin << "', "
305                 "CAST('" << date << "' AS DATE), "
306                 "CAST(" << dir << " AS SMALLINT), "
307                 "CAST(" << stat.monthUp[dir] << " AS BIGINT), "
308                 "CAST(" << stat.monthDown[dir] << " AS BIGINT))";
309
310     result = PQexec(connection, query.str().c_str());
311
312     if (PQresultStatus(result) != PGRES_TUPLES_OK)
313         {
314         strError = PQresultErrorMessage(result);
315         PQclear(result);
316         printfd(__FILE__, "POSTGRESQL_STORE::SaveStat(): '%s'\n", strError.c_str());
317         if (RollbackTransaction())
318             {
319             printfd(__FILE__, "POSTGRESQL_STORE::SaveStat(): 'Failed to rollback transaction'\n");
320             }
321         return -1;
322         }
323
324     PQclear(result);
325     }
326
327 if (CommitTransaction())
328     {
329     printfd(__FILE__, "POSTGRESQL_STORE::SaveStat(): 'Failed to commit transaction'\n");
330     return -1;
331     }
332
333 return 0;
334 }
335
336 //-----------------------------------------------------------------------------
337 int POSTGRESQL_STORE::SaveUserConf(const USER_CONF & conf,
338                                  const std::string & login) const
339 {
340 STG_LOCKER lock(&mutex);
341
342 if (PQstatus(connection) != CONNECTION_OK)
343     {
344     printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): 'Connection lost. Trying to reconnect...'\n", strError.c_str());
345     if (Reset())
346         {
347         strError = "Connection lost";
348         printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): '%s'\n", strError.c_str());
349         return -1;
350         }
351     }
352
353 PGresult * result;
354
355 if (StartTransaction())
356     {
357     printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): 'Failed to start transaction'\n");
358     return -1;
359     }
360
361 std::string elogin = login;
362
363 if (EscapeString(elogin))
364     {
365     printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): 'Failed to escape login'\n");
366     if (RollbackTransaction())
367         {
368         printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): 'Failed to rollback transaction'\n");
369         }
370     return -1;
371     }
372
373 std::ostringstream query;
374 query << "SELECT pk_user FROM tb_users WHERE name = '" << elogin << "'";
375
376 result = PQexec(connection, query.str().c_str());
377
378 if (PQresultStatus(result) != PGRES_TUPLES_OK)
379     {
380     strError = PQresultErrorMessage(result);
381     PQclear(result);
382     printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): '%s'\n", strError.c_str());
383     if (RollbackTransaction())
384         {
385         printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): 'Failed to rollback transaction'\n");
386         }
387     return -1;
388     }
389
390 int tuples = PQntuples(result);
391
392 if (tuples != 1)
393     {
394     strError = "Failed to fetch user's ID";
395     printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): 'Invalid number of tuples. Wanted 1, actulally %d'\n", tuples);
396     PQclear(result);
397     if (RollbackTransaction())
398         {
399         printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): 'Failed to rollback transaction'\n");
400         }
401     return -1;
402     }
403
404 uint32_t uid;
405
406     {
407     std::stringstream tuple;
408     tuple << PQgetvalue(result, 0, 0);
409
410     PQclear(result);
411
412     tuple >> uid;
413     }
414
415 std::string eaddress = conf.address;
416 std::string eemail = conf.email;
417 std::string egroup = conf.group;
418 std::string enote = conf.note;
419 std::string epassword = conf.password;
420 std::string ephone = conf.phone;
421 std::string erealname = conf.realName;
422 std::string etariffname = conf.tariffName;
423 std::string enexttariff = conf.nextTariff;
424 std::string ecorporation = conf.corp;
425
426 if (EscapeString(eaddress))
427     {
428     printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): 'Failed to escape address'\n");
429     if (RollbackTransaction())
430         {
431         printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): 'Failed to rollback transaction'\n");
432         }
433     return -1;
434     }
435
436 if (EscapeString(eemail))
437     {
438     printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): 'Failed to escape email'\n");
439     if (RollbackTransaction())
440         {
441         printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): 'Failed to rollback transaction'\n");
442         }
443     return -1;
444     }
445
446 if (EscapeString(egroup))
447     {
448     printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): 'Failed to escape group'\n");
449     if (RollbackTransaction())
450         {
451         printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): 'Failed to rollback transaction'\n");
452         }
453     return -1;
454     }
455
456 if (EscapeString(enote))
457     {
458     printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): 'Failed to escape note'\n");
459     if (RollbackTransaction())
460         {
461         printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): 'Failed to rollback transaction'\n");
462         }
463     return -1;
464     }
465
466 if (EscapeString(epassword))
467     {
468     printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): 'Failed to escape password'\n");
469     if (RollbackTransaction())
470         {
471         printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): 'Failed to rollback transaction'\n");
472         }
473     return -1;
474     }
475
476 if (EscapeString(ephone))
477     {
478     printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): 'Failed to escape phone'\n");
479     if (RollbackTransaction())
480         {
481         printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): 'Failed to rollback transaction'\n");
482         }
483     return -1;
484     }
485
486 if (EscapeString(erealname))
487     {
488     printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): 'Failed to escape real name'\n");
489     if (RollbackTransaction())
490         {
491         printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): 'Failed to rollback transaction'\n");
492         }
493     return -1;
494     }
495
496 if (EscapeString(etariffname))
497     {
498     printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): 'Failed to escape tariff name'\n");
499     if (RollbackTransaction())
500         {
501         printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): 'Failed to rollback transaction'\n");
502         }
503     return -1;
504     }
505
506 if (EscapeString(enexttariff))
507     {
508     printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): 'Failed to escape next tariff name'\n");
509     if (RollbackTransaction())
510         {
511         printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): 'Failed to rollback transaction'\n");
512         }
513     return -1;
514     }
515
516 if (EscapeString(ecorporation))
517     {
518     printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): 'Failed to escape corporation name'\n");
519     if (RollbackTransaction())
520         {
521         printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): 'Failed to rollback transaction'\n");
522         }
523     return -1;
524     }
525
526 query.str("");
527 query << "UPDATE tb_users SET "
528              "address = '" << eaddress << "', "
529              "always_online = " << (conf.alwaysOnline ? "'t'" : "'f'") << ", "
530              "credit = " << conf.credit << ", "
531              "credit_expire = CAST('" << formatTime(conf.creditExpire) << "' AS TIMESTAMP), "
532              "disabled = " << (conf.disabled ? "'t'" : "'f'") << ", "
533              "disabled_detail_stat = " << (conf.disabledDetailStat ? "'t'" : "'f'") << ", "
534              "email = '" << eemail << "', "
535              "grp = '" << egroup << "', "
536              "note = '" << enote << "', "
537              "passive = " << (conf.passive ? "'t'" : "'f'") << ", "
538              "passwd = '" << epassword << "', "
539              "phone = '" << ephone << "', "
540              "real_name = '" << erealname << "', "
541              "fk_tariff = (SELECT pk_tariff "
542                    "FROM tb_tariffs "
543                    "WHERE name = '" << etariffname << "'), "
544              "fk_tariff_change = (SELECT pk_tariff "
545                    "FROM tb_tariffs "
546                    "WHERE name = '" << enexttariff << "'), "
547              "fk_corporation = (SELECT pk_corporation "
548                    "FROM tb_corporations "
549                    "WHERE name = '" << ecorporation << "') "
550          "WHERE pk_user = " << uid;
551
552 result = PQexec(connection, query.str().c_str());
553
554 if (PQresultStatus(result) != PGRES_COMMAND_OK)
555     {
556     strError = PQresultErrorMessage(result);
557     PQclear(result);
558     printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): '%s'\n", strError.c_str());
559     if (RollbackTransaction())
560         {
561         printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): 'Failed to rollback transaction'\n");
562         }
563     return -1;
564     }
565
566 PQclear(result);
567
568 if (SaveUserServices(uid, conf.services))
569     {
570     printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): 'Failed to save user's services'\n");
571     if (RollbackTransaction())
572         {
573         printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): 'Failed to rollback transaction'\n");
574         }
575     return -1;
576     }
577
578 if (SaveUserData(uid, conf.userdata))
579     {
580     printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): 'Failed to save user's data'\n");
581     if (RollbackTransaction())
582         {
583         printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): 'Failed to rollback transaction'\n");
584         }
585     return -1;
586     }
587
588 if (SaveUserIPs(uid, conf.ips))
589     {
590     printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): 'Failed to save user's IPs'\n");
591     if (RollbackTransaction())
592         {
593         printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): 'Failed to rollback transaction'\n");
594         }
595     return -1;
596     }
597
598 if (CommitTransaction())
599     {
600     printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): 'Failed to commit transaction'\n");
601     return -1;
602     }
603
604 return 0;
605 }
606
607 //-----------------------------------------------------------------------------
608 int POSTGRESQL_STORE::RestoreUserStat(USER_STAT * stat,
609                                     const std::string & login) const
610 {
611 STG_LOCKER lock(&mutex);
612
613 if (PQstatus(connection) != CONNECTION_OK)
614     {
615     printfd(__FILE__, "POSTGRESQL_STORE::RestoreUserStat(): 'Connection lost. Trying to reconnect...'\n", strError.c_str());
616     if (Reset())
617         {
618         strError = "Connection lost";
619         printfd(__FILE__, "POSTGRESQL_STORE::RestoreUserStat(): '%s'\n", strError.c_str());
620         return -1;
621         }
622     }
623
624 PGresult * result;
625
626 if (StartTransaction())
627     {
628     printfd(__FILE__, "POSTGRESQL_STORE::RestoreUserStat(): 'Failed to start transaction'\n");
629     return -1;
630     }
631
632 std::string elogin = login;
633
634 if (EscapeString(elogin))
635     {
636     printfd(__FILE__, "POSTGRESQL_STORE::RestoreUserStat(): 'Failed to escape login'\n");
637     if (RollbackTransaction())
638         {
639         printfd(__FILE__, "POSTGRESQL_STORE::RestoreUserStat(): 'Failed to rollback transaction'\n");
640         }
641     return -1;
642     }
643
644     {
645     std::ostringstream query;
646     query << "SELECT cash, free_mb, "
647                 "last_activity_time, last_cash_add, "
648                 "last_cash_add_time, passive_time "
649              "FROM tb_users "
650              "WHERE name = '" << elogin << "'";
651
652     result = PQexec(connection, query.str().c_str());
653     }
654
655 if (PQresultStatus(result) != PGRES_TUPLES_OK)
656     {
657     strError = PQresultErrorMessage(result);
658     printfd(__FILE__, "POSTGRESQL_STORE::RestoreUserStat(): '%s'\n", strError.c_str());
659     PQclear(result);
660     if (RollbackTransaction())
661         {
662         printfd(__FILE__, "POSTGRESQL_STORE::RestoreUserStat(): 'Failed to rollback transaction'\n");
663         }
664     return -1;
665     }
666
667 int tuples = PQntuples(result);
668
669 if (tuples != 1)
670     {
671     strError = "Failed to fetch user's stat";
672     printfd(__FILE__, "POSTGRESQL_STORE::RestoreUserStat(): 'Invalid number of tuples. Wanted 1, actulally %d'\n", tuples);
673     PQclear(result);
674     if (RollbackTransaction())
675         {
676         printfd(__FILE__, "POSTGRESQL_STORE::RestoreUserStat(): 'Failed to rollback transaction'\n");
677         }
678     return -1;
679     }
680
681     {
682     std::stringstream tuple;
683     tuple << PQgetvalue(result, 0, 0) << " ";
684     tuple << PQgetvalue(result, 0, 1) << " ";
685     stat->lastActivityTime = readTime(PQgetvalue(result, 0, 2));
686     tuple << PQgetvalue(result, 0, 3) << " ";
687     stat->lastCashAddTime = readTime(PQgetvalue(result, 0, 4));
688     tuple << PQgetvalue(result, 0, 5) << " ";
689
690     PQclear(result);
691
692     tuple >> stat->cash
693           >> stat->freeMb
694           >> stat->lastCashAdd
695           >> stat->passiveTime;
696     }
697
698     {
699     std::ostringstream query;
700     query << "SELECT dir_num, upload, download "
701              "FROM tb_stats_traffic "
702              "WHERE fk_user IN (SELECT pk_user FROM tb_users WHERE name = '" << elogin << "') AND "
703                    "DATE_TRUNC('month', stats_date) = DATE_TRUNC('month', CAST('" << formatTime(stgTime) << "' AS TIMESTAMP))";
704
705     result = PQexec(connection, query.str().c_str());
706     }
707
708 if (PQresultStatus(result) != PGRES_TUPLES_OK)
709     {
710     strError = PQresultErrorMessage(result);
711     printfd(__FILE__, "POSTGRESQL_STORE::RestoreUserStat(): '%s'\n", strError.c_str());
712     PQclear(result);
713     if (RollbackTransaction())
714         {
715         printfd(__FILE__, "POSTGRESQL_STORE::RestoreUserStat(): 'Failed to rollback transaction'\n");
716         }
717     return -1;
718     }
719
720 tuples = PQntuples(result);
721
722 for (int i = 0; i < tuples; ++i)
723     {
724     std::stringstream tuple;
725     tuple << PQgetvalue(result, i, 0) << " ";
726     tuple << PQgetvalue(result, i, 1) << " ";
727     tuple << PQgetvalue(result, i, 2) << " ";
728
729     int dir;
730
731     tuple >> dir;
732     tuple >> stat->monthUp[dir];
733     tuple >> stat->monthDown[dir];
734     }
735
736 PQclear(result);
737
738 if (CommitTransaction())
739     {
740     printfd(__FILE__, "POSTGRESQL_STORE::RestoreUserStat(): 'Failed to commit transaction'\n");
741     return -1;
742     }
743
744 return 0;
745 }
746
747 //-----------------------------------------------------------------------------
748 int POSTGRESQL_STORE::RestoreUserConf(USER_CONF * conf,
749                                     const std::string & login) const
750 {
751 STG_LOCKER lock(&mutex);
752
753 if (PQstatus(connection) != CONNECTION_OK)
754     {
755     printfd(__FILE__, "POSTGRESQL_STORE::RestoreUserConf(): 'Connection lost. Trying to reconnect...'\n", strError.c_str());
756     if (Reset())
757         {
758         strError = "Connection lost";
759         printfd(__FILE__, "POSTGRESQL_STORE::RestoreUserConf(): '%s'\n", strError.c_str());
760         return -1;
761         }
762     }
763
764 PGresult * result;
765
766 if (StartTransaction())
767     {
768     printfd(__FILE__, "POSTGRESQL_STORE::RestoreUserStat(): 'Failed to start transaction'\n");
769     return -1;
770     }
771
772 std::string elogin = login;
773
774 if (EscapeString(elogin))
775     {
776     printfd(__FILE__, "POSTGRESQL_STORE::RestoreUserStat(): 'Failed to escape login'\n");
777     if (RollbackTransaction())
778         {
779         printfd(__FILE__, "POSTGRESQL_STORE::RestoreUserStat(): 'Failed to rollback transaction'\n");
780         }
781     return -1;
782     }
783
784     {
785     std::ostringstream query;
786     query << "SELECT tb_users.pk_user, tb_users.address, tb_users.always_online, "
787                     "tb_users.credit, tb_users.credit_expire, tb_users.disabled, "
788                     "tb_users.disabled_detail_stat, tb_users.email, tb_users.grp, "
789                     "tb_users.note, tb_users.passive, tb_users.passwd, tb_users.phone, "
790                     "tb_users.real_name, tf1.name, tf2.name, tb_corporations.name "
791              "FROM tb_users LEFT JOIN tb_tariffs AS tf1 "
792                                 "ON tf1.pk_tariff = tb_users.fk_tariff "
793                            "LEFT JOIN tb_tariffs AS tf2 "
794                                 "ON tf2.pk_tariff = tb_users.fk_tariff_change "
795                            "LEFT JOIN tb_corporations "
796                                 "ON tb_corporations.pk_corporation = tb_users.fk_corporation "
797              "WHERE tb_users.name = '" << elogin << "'";
798
799     result = PQexec(connection, query.str().c_str());
800     }
801
802 if (PQresultStatus(result) != PGRES_TUPLES_OK)
803     {
804     strError = PQresultErrorMessage(result);
805     printfd(__FILE__, "POSTGRESQL_STORE::RestoreUserConf(): '%s'\n", strError.c_str());
806     PQclear(result);
807     if (RollbackTransaction())
808         {
809         printfd(__FILE__, "POSTGRESQL_STORE::RestoreUserConf(): 'Failed to rollback transaction'\n");
810         }
811     return -1;
812     }
813
814 int tuples = PQntuples(result);
815
816 if (tuples != 1)
817     {
818     strError = "Failed to fetch user's stat";
819     printfd(__FILE__, "POSTGRESQL_STORE::RestoreUserConf(): 'Invalid number of tuples. Wanted 1, actulally %d'\n", tuples);
820     PQclear(result);
821     if (RollbackTransaction())
822         {
823         printfd(__FILE__, "POSTGRESQL_STORE::RestoreUserConf(): 'Failed to rollback transaction'\n");
824         }
825     return -1;
826     }
827
828 uint32_t uid;
829
830     {
831     std::stringstream tuple;
832     tuple << PQgetvalue(result, 0, 0) << " ";               // uid
833     conf->address = PQgetvalue(result, 0, 1);               // address
834     conf->alwaysOnline = !strncmp(PQgetvalue(result, 0, 2), "t", 1);
835     tuple << PQgetvalue(result, 0, 3) << " ";               // credit
836     conf->creditExpire = readTime(PQgetvalue(result, 0, 4));  // creditExpire
837     conf->disabled = !strncmp(PQgetvalue(result, 0, 5), "t", 1);
838     conf->disabledDetailStat = !strncmp(PQgetvalue(result, 0, 6), "t", 1);
839     conf->email = PQgetvalue(result, 0, 7);                 // email
840     conf->group = PQgetvalue(result, 0, 8);                 // group
841     conf->note = PQgetvalue(result, 0, 9);                  // note
842     conf->passive = !strncmp(PQgetvalue(result, 0, 10), "t", 1);
843     conf->password = PQgetvalue(result, 0, 11);             // password
844     conf->phone = PQgetvalue(result, 0, 12);                // phone
845     conf->realName = PQgetvalue(result, 0, 13);             // realName
846     conf->tariffName = PQgetvalue(result, 0, 14);           // tariffName
847     conf->nextTariff = PQgetvalue(result, 0, 15);           // nextTariff
848     conf->corp = PQgetvalue(result, 0, 16);                 // corp
849
850     PQclear(result);
851
852     if (conf->tariffName == "")
853         conf->tariffName = NO_TARIFF_NAME;
854     if (conf->corp == "")
855         conf->corp = NO_CORP_NAME;
856
857     tuple >> uid
858           >> conf->credit;
859     }
860
861     {
862     std::ostringstream query;
863     query << "SELECT name FROM tb_services "
864              "WHERE pk_service IN (SELECT fk_service "
865                                   "FROM tb_users_services "
866                                   "WHERE fk_user = " << uid << ")";
867
868     result = PQexec(connection, query.str().c_str());
869     }
870
871 if (PQresultStatus(result) != PGRES_TUPLES_OK)
872     {
873     strError = PQresultErrorMessage(result);
874     printfd(__FILE__, "POSTGRESQL_STORE::RestoreUserConf(): '%s'\n", strError.c_str());
875     PQclear(result);
876     if (RollbackTransaction())
877         {
878         printfd(__FILE__, "POSTGRESQL_STORE::RestoreUserConf(): 'Failed to rollback transaction'\n");
879         }
880     return -1;
881     }
882
883 tuples = PQntuples(result);
884
885 for (int i = 0; i < tuples; ++i)
886     {
887     conf->services.push_back(PQgetvalue(result, i, 0));
888     }
889
890 PQclear(result);
891
892     {
893     std::ostringstream query;
894     query << "SELECT num, data "
895              "FROM tb_users_data "
896              "WHERE fk_user = " << uid;
897
898     result = PQexec(connection, query.str().c_str());
899     }
900
901 if (PQresultStatus(result) != PGRES_TUPLES_OK)
902     {
903     strError = PQresultErrorMessage(result);
904     printfd(__FILE__, "POSTGRESQL_STORE::RestoreUserConf(): '%s'\n", strError.c_str());
905     PQclear(result);
906     if (RollbackTransaction())
907         {
908         printfd(__FILE__, "POSTGRESQL_STORE::RestoreUserConf(): 'Failed to rollback transaction'\n");
909         }
910     return -1;
911     }
912
913 tuples = PQntuples(result);
914
915 for (int i = 0; i < tuples; ++i)
916     {
917     int num;
918     if (str2x(PQgetvalue(result, i, 0), num))
919         {
920         printfd(__FILE__, "POSTGRESQL_STORE::RestoreUserConf(): 'Failed to convert string to int'\n");
921         }
922     else
923         {
924         if (num < USERDATA_NUM &&
925             num >= 0)
926             {
927             conf->userdata[num] = PQgetvalue(result, i, 1);
928             }
929         }
930     }
931
932 PQclear(result);
933
934     {
935     std::ostringstream query;
936     query << "SELECT host(ip), masklen(ip) "
937              "FROM tb_allowed_ip "
938              "WHERE fk_user = " << uid;
939
940     result = PQexec(connection, query.str().c_str());
941     }
942
943 if (PQresultStatus(result) != PGRES_TUPLES_OK)
944     {
945     strError = PQresultErrorMessage(result);
946     printfd(__FILE__, "POSTGRESQL_STORE::RestoreUserConf(): '%s'\n", strError.c_str());
947     PQclear(result);
948     if (RollbackTransaction())
949         {
950         printfd(__FILE__, "POSTGRESQL_STORE::RestoreUserConf(): 'Failed to rollback transaction'\n");
951         }
952     return -1;
953     }
954
955 tuples = PQntuples(result);
956
957 USER_IPS ips;
958 for (int i = 0; i < tuples; ++i)
959     {
960     IP_MASK im;
961
962     im.ip = inet_strington(PQgetvalue(result, i, 0));
963
964     if (str2x(PQgetvalue(result, i, 1), im.mask))
965         {
966         printfd(__FILE__, "POSTGRESQL_STORE::RestoreUserConf(): 'Failed to fetch mask'\n");
967         continue;
968         }
969
970     ips.Add(im);
971     }
972 conf->ips = ips;
973
974 PQclear(result);
975
976 if (CommitTransaction())
977     {
978     printfd(__FILE__, "POSTGRESQL_STORE::RestoreUserConf(): 'Failed to commit transaction'\n");
979     return -1;
980     }
981
982 return 0;
983 }
984
985 //-----------------------------------------------------------------------------
986 int POSTGRESQL_STORE::WriteUserChgLog(const std::string & login,
987                                     const std::string & admLogin,
988                                     uint32_t admIP,
989                                     const std::string & paramName,
990                                     const std::string & oldValue,
991                                     const std::string & newValue,
992                                     const std::string & message = "") const
993 {
994 STG_LOCKER lock(&mutex);
995
996 if (PQstatus(connection) != CONNECTION_OK)
997     {
998     printfd(__FILE__, "POSTGRESQL_STORE::WriteUserChgLog(): 'Connection lost. Trying to reconnect...'\n", strError.c_str());
999     if (Reset())
1000         {
1001         strError = "Connection lost";
1002         printfd(__FILE__, "POSTGRESQL_STORE::WriteUserChgLog(): '%s'\n", strError.c_str());
1003         return -1;
1004         }
1005     }
1006
1007 PGresult * result;
1008
1009 if (StartTransaction())
1010     {
1011     printfd(__FILE__, "POSTGRESQL_STORE::WriteUserChgLog(): 'Failed to start transaction'\n");
1012     return -1;
1013     }
1014
1015 std::string elogin(login);
1016 std::string eadminLogin(admLogin);
1017 std::string eparam(paramName);
1018 std::string eold(oldValue);
1019 std::string enew(newValue);
1020 std::string emessage(message);
1021
1022 if (EscapeString(elogin))
1023     {
1024     printfd(__FILE__, "POSTGRESQL_STORE::WriteUserChgLog(): 'Failed to escape login'\n");
1025     if (RollbackTransaction())
1026         {
1027         printfd(__FILE__, "POSTGRESQL_STORE::WriteUserChgLog(): 'Failed to rollback transaction'\n");
1028         }
1029     return -1;
1030     }
1031
1032 if (EscapeString(eadminLogin))
1033     {
1034     printfd(__FILE__, "POSTGRESQL_STORE::WriteUserChgLog(): 'Failed to escape admin's login'\n");
1035     if (RollbackTransaction())
1036         {
1037         printfd(__FILE__, "POSTGRESQL_STORE::WriteUserChgLog(): 'Failed to rollback transaction'\n");
1038         }
1039     return -1;
1040     }
1041
1042 if (EscapeString(eparam))
1043     {
1044     printfd(__FILE__, "POSTGRESQL_STORE::WriteUserChgLog(): 'Failed to escape param's name'\n");
1045     if (RollbackTransaction())
1046         {
1047         printfd(__FILE__, "POSTGRESQL_STORE::WriteUserChgLog(): 'Failed to rollback transaction'\n");
1048         }
1049     return -1;
1050     }
1051
1052 if (EscapeString(eold))
1053     {
1054     printfd(__FILE__, "POSTGRESQL_STORE::WriteUserChgLog(): 'Failed to escape old value'\n");
1055     if (RollbackTransaction())
1056         {
1057         printfd(__FILE__, "POSTGRESQL_STORE::WriteUserChgLog(): 'Failed to rollback transaction'\n");
1058         }
1059     return -1;
1060     }
1061
1062 if (EscapeString(enew))
1063     {
1064     printfd(__FILE__, "POSTGRESQL_STORE::WriteUserChgLog(): 'Failed to escape new value'\n");
1065     if (RollbackTransaction())
1066         {
1067         printfd(__FILE__, "POSTGRESQL_STORE::WriteUserChgLog(): 'Failed to rollback transaction'\n");
1068         }
1069     return -1;
1070     }
1071
1072 std::ostringstream query;
1073 query << "SELECT sp_add_param_log_entry("
1074             "'" << elogin << "', "
1075             "'" << eadminLogin << "', CAST('"
1076             << inet_ntostring(admIP) << "/32' AS INET), "
1077             "'" << eparam << "', "
1078             "CAST('" << formatTime(stgTime) << "' AS TIMESTAMP), "
1079             "'" << eold << "', "
1080             "'" << enew << "', "
1081             "'" << emessage << "')";
1082
1083 result = PQexec(connection, query.str().c_str());
1084
1085 if (PQresultStatus(result) != PGRES_TUPLES_OK)
1086     {
1087     strError = PQresultErrorMessage(result);
1088     PQclear(result);
1089     printfd(__FILE__, "POSTGRESQL_STORE::WriteUserChgLog(): '%s'\n", strError.c_str());
1090     if (RollbackTransaction())
1091         {
1092         printfd(__FILE__, "POSTGRESQL_STORE::WriteUserChgLog(): 'Failed to rollback transaction'\n");
1093         }
1094     return -1;
1095     }
1096
1097 PQclear(result);
1098
1099 if (CommitTransaction())
1100     {
1101     printfd(__FILE__, "POSTGRESQL_STORE::WriteUserChgLog(): 'Failed to commit transaction'\n");
1102     return -1;
1103     }
1104
1105 return 0;
1106 }
1107
1108 //-----------------------------------------------------------------------------
1109 int POSTGRESQL_STORE::WriteUserConnect(const std::string & login, uint32_t ip) const
1110 {
1111 STG_LOCKER lock(&mutex);
1112
1113 if (PQstatus(connection) != CONNECTION_OK)
1114     {
1115     printfd(__FILE__, "POSTGRESQL_STORE::WriteUserConnect(): 'Connection lost. Trying to reconnect...'\n", strError.c_str());
1116     if (Reset())
1117         {
1118         strError = "Connection lost";
1119         printfd(__FILE__, "POSTGRESQL_STORE::WriteUserConnect(): '%s'\n", strError.c_str());
1120         return -1;
1121         }
1122     }
1123
1124 PGresult * result;
1125
1126 if (StartTransaction())
1127     {
1128     printfd(__FILE__, "POSTGRESQL_STORE::WriteUserConnect(): 'Failed to start transaction'\n");
1129     return -1;
1130     }
1131
1132 std::string elogin(login);
1133
1134 if (EscapeString(elogin))
1135     {
1136     printfd(__FILE__, "POSTGRESQL_STORE::WriteUserConnect(): 'Failed to escape login'\n");
1137     if (RollbackTransaction())
1138         {
1139         printfd(__FILE__, "POSTGRESQL_STORE::WriteUserConnect(): 'Failed to rollback transaction'\n");
1140         }
1141     return -1;
1142     }
1143
1144 std::ostringstream query;
1145 if (version < 6)
1146     {
1147     query << "SELECT sp_add_session_log_entry("
1148                  "'" << elogin << "', "
1149                  "CAST('" << formatTime(stgTime) << "' AS TIMESTAMP), "
1150                  "'c', CAST('"
1151                  << inet_ntostring(ip) << "/32' AS INET), 0)";
1152     }
1153 else
1154     {
1155     query << "SELECT sp_add_session_log_entry("
1156                  "'" << elogin << "', "
1157                  "CAST('" << formatTime(stgTime) << "' AS TIMESTAMP), "
1158                  "'c', CAST('"
1159                  << inet_ntostring(ip) << "/32' AS INET), 0, 0, '')";
1160     }
1161
1162 result = PQexec(connection, query.str().c_str());
1163
1164 if (PQresultStatus(result) != PGRES_TUPLES_OK)
1165     {
1166     strError = PQresultErrorMessage(result);
1167     PQclear(result);
1168     printfd(__FILE__, "POSTGRESQL_STORE::WriteUserConnect(): '%s'\n", strError.c_str());
1169     if (RollbackTransaction())
1170         {
1171         printfd(__FILE__, "POSTGRESQL_STORE::WriteUserConnect(): 'Failed to rollback transaction'\n");
1172         }
1173     return -1;
1174     }
1175
1176 PQclear(result);
1177
1178 if (CommitTransaction())
1179     {
1180     printfd(__FILE__, "POSTGRESQL_STORE::WriteUserConnect(): 'Failed to commit transaction'\n");
1181     return -1;
1182     }
1183
1184 return 0;
1185 }
1186
1187 //-----------------------------------------------------------------------------
1188 int POSTGRESQL_STORE::WriteUserDisconnect(const std::string & login,
1189                     const DIR_TRAFF & monthUp,
1190                     const DIR_TRAFF & monthDown,
1191                     const DIR_TRAFF & sessionUp,
1192                     const DIR_TRAFF & sessionDown,
1193                     double cash,
1194                     double freeMb,
1195                     const std::string & reason) const
1196 {
1197 STG_LOCKER lock(&mutex);
1198
1199 if (PQstatus(connection) != CONNECTION_OK)
1200     {
1201     printfd(__FILE__, "POSTGRESQL_STORE::WriteUserDisconnect(): 'Connection lost. Trying to reconnect...'\n", strError.c_str());
1202     if (Reset())
1203         {
1204         strError = "Connection lost";
1205         printfd(__FILE__, "POSTGRESQL_STORE::WriteUserDisconnect(): '%s'\n", strError.c_str());
1206         return -1;
1207         }
1208     }
1209
1210 PGresult * result;
1211
1212 if (StartTransaction())
1213     {
1214     printfd(__FILE__, "POSTGRESQL_STORE::WriteUserDisconnect(): 'Failed to start transaction'\n");
1215     return -1;
1216     }
1217
1218 std::string elogin(login);
1219
1220 if (EscapeString(elogin))
1221     {
1222     printfd(__FILE__, "POSTGRESQL_STORE::WriteUserDisconnect(): 'Failed to escape login'\n");
1223     if (RollbackTransaction())
1224         {
1225         printfd(__FILE__, "POSTGRESQL_STORE::WriteUserDisconnect(): 'Failed to rollback transaction'\n");
1226         }
1227     return -1;
1228     }
1229
1230 std::string ereason(reason);
1231
1232 if (EscapeString(ereason))
1233     {
1234     printfd(__FILE__, "POSTGRESQL_STORE::WriteUserDisconnect(): 'Failed to escape reason'\n");
1235     if (RollbackTransaction())
1236         {
1237         printfd(__FILE__, "POSTGRESQL_STORE::WriteUserDisconnect(): 'Failed to rollback transaction'\n");
1238         }
1239     return -1;
1240     }
1241
1242     {
1243     std::ostringstream query;
1244     if (version < 6)
1245         {
1246         // Old database version - no freeMb logging support
1247         query << "SELECT sp_add_session_log_entry("
1248                     "'" << elogin << "', "
1249                     "CAST('" << formatTime(stgTime) << "' AS TIMESTAMP), "
1250                     "'d', CAST('0.0.0.0/0' AS INET), "
1251                     << cash << ")";
1252         }
1253     else
1254         {
1255         query << "SELECT sp_add_session_log_entry("
1256                     "'" << elogin << "', "
1257                     "CAST('" << formatTime(stgTime) << "' AS TIMESTAMP), "
1258                     "'d', CAST('0.0.0.0/0' AS INET), "
1259                     << cash << ", " << freeMb << ", '" << ereason << "')";
1260         }
1261
1262     result = PQexec(connection, query.str().c_str());
1263     }
1264
1265 if (PQresultStatus(result) != PGRES_TUPLES_OK)
1266     {
1267     strError = PQresultErrorMessage(result);
1268     PQclear(result);
1269     printfd(__FILE__, "POSTGRESQL_STORE::WriteUserDisconnect(): '%s'\n", strError.c_str());
1270     if (RollbackTransaction())
1271         {
1272         printfd(__FILE__, "POSTGRESQL_STORE::WriteUserDisconnect(): 'Failed to rollback transaction'\n");
1273         }
1274     return -1;
1275     }
1276
1277 int tuples = PQntuples(result);
1278
1279 if (tuples != 1)
1280     {
1281     strError = "Failed to fetch session's log ID";
1282     printfd(__FILE__, "POSTGRESQL_STORE::WriteUserDisconnect(): 'Invalid number of tuples. Wanted 1, actulally %d'\n", tuples);
1283     PQclear(result);
1284     if (RollbackTransaction())
1285         {
1286         printfd(__FILE__, "POSTGRESQL_STORE::WriteUserDisconnect(): 'Failed to rollback transaction'\n");
1287         }
1288     return -1;
1289     }
1290
1291 uint32_t lid;
1292
1293 if (str2x(PQgetvalue(result, 0, 0), lid))
1294     {
1295     strError = "Failed to convert string to int";
1296     printfd(__FILE__, "POSTGRESQL_STORE::WriteUserDisconnect(): '%s'\n", strError.c_str());
1297     PQclear(result);
1298     if (RollbackTransaction())
1299         {
1300         printfd(__FILE__, "POSTGRESQL_STORE::WriteUserDisconnect(): 'Failed to rollback transaction'\n");
1301         }
1302     return -1;
1303     }
1304
1305 PQclear(result);
1306
1307 for (int i = 0; i < DIR_NUM; ++i)
1308     {
1309     std::ostringstream query;
1310     query << "INSERT INTO tb_sessions_data "
1311                 "(fk_session_log, "
1312                  "dir_num, "
1313                  "session_upload, "
1314                  "session_download, "
1315                  "month_upload, "
1316                  "month_download)"
1317              "VALUES ("
1318                 << lid << ", "
1319                 << i << ", "
1320                 << sessionUp[i] << ", "
1321                 << sessionDown[i] << ", "
1322                 << monthUp[i] << ", "
1323                 << monthDown[i] << ")";
1324
1325     result = PQexec(connection, query.str().c_str());
1326
1327     if (PQresultStatus(result) != PGRES_COMMAND_OK)
1328         {
1329         strError = PQresultErrorMessage(result);
1330         PQclear(result);
1331         printfd(__FILE__, "POSTGRESQL_STORE::WriteUserDisconnect(): '%s'\n", strError.c_str());
1332         if (RollbackTransaction())
1333             {
1334             printfd(__FILE__, "POSTGRESQL_STORE::WriteUserDisconnect(): 'Failed to rollback transaction'\n");
1335             }
1336         return -1;
1337         }
1338
1339     PQclear(result);
1340     }
1341
1342 if (CommitTransaction())
1343     {
1344     printfd(__FILE__, "POSTGRESQL_STORE::WriteUserDisconnect(): 'Failed to commit transaction'\n");
1345     return -1;
1346     }
1347
1348 return 0;
1349 }
1350
1351 //-----------------------------------------------------------------------------
1352 int POSTGRESQL_STORE::WriteDetailedStat(const std::map<IP_DIR_PAIR, STAT_NODE> & statTree,
1353                                       time_t lastStat,
1354                                       const std::string & login) const
1355 {
1356 STG_LOCKER lock(&mutex);
1357
1358 if (PQstatus(connection) != CONNECTION_OK)
1359     {
1360     printfd(__FILE__, "POSTGRESQL_STORE::WriteDetailedStat(): 'Connection lost. Trying to reconnect...'\n", strError.c_str());
1361     if (Reset())
1362         {
1363         strError = "Connection lost";
1364         printfd(__FILE__, "POSTGRESQL_STORE::WriteDetailedStat(): '%s'\n", strError.c_str());
1365         return -1;
1366         }
1367     }
1368
1369 if (StartTransaction())
1370     {
1371     printfd(__FILE__, "POSTGRESQL_STORE::WriteDetailedStat(): 'Failed to start transaction'\n");
1372     return -1;
1373     }
1374
1375 std::string elogin(login);
1376
1377 if (EscapeString(elogin))
1378     {
1379     printfd(__FILE__, "POSTGRESQL_STORE::WriteDetailedStat(): 'Failed to escape login'\n");
1380     if (RollbackTransaction())
1381         {
1382         printfd(__FILE__, "POSTGRESQL_STORE::WriteDetailedStat(): 'Failed to rollback transaction'\n");
1383         }
1384     return -1;
1385     }
1386
1387 std::map<IP_DIR_PAIR, STAT_NODE>::const_iterator it;
1388 time_t currTime = time(NULL);
1389
1390 for (it = statTree.begin(); it != statTree.end(); ++it)
1391     {
1392     std::ostringstream query;
1393     query << "INSERT INTO tb_detail_stats "
1394                 "(till_time, from_time, fk_user, "
1395                  "dir_num, ip, download, upload, cost) "
1396              "VALUES ("
1397                 "CAST('" << formatTime(currTime) << "' AS TIMESTAMP), "
1398                 "CAST('" << formatTime(lastStat) << "' AS TIMESTAMP), "
1399                 "(SELECT pk_user FROM tb_users WHERE name = '" << elogin << "'), "
1400                 << it->first.dir << ", "
1401                 << "CAST('" << inet_ntostring(it->first.ip) << "' AS INET), "
1402                 << it->second.down << ", "
1403                 << it->second.up << ", "
1404                 << it->second.cash << ")";
1405
1406     PGresult * result = PQexec(connection, query.str().c_str());
1407
1408     if (PQresultStatus(result) != PGRES_COMMAND_OK)
1409         {
1410         strError = PQresultErrorMessage(result);
1411         PQclear(result);
1412         printfd(__FILE__, "POSTGRESQL_STORE::WriteDetailedStat(): '%s'\n", strError.c_str());
1413         if (RollbackTransaction())
1414             {
1415             printfd(__FILE__, "POSTGRESQL_STORE::WriteDetailedStat(): 'Failed to rollback transaction'\n");
1416             }
1417         return -1;
1418         }
1419
1420     PQclear(result);
1421     }
1422
1423 if (CommitTransaction())
1424     {
1425     printfd(__FILE__, "POSTGRESQL_STORE::WriteDetailedStat(): 'Failed to commit transaction'\n");
1426     return -1;
1427     }
1428
1429 return 0;
1430 }
1431
1432 //-----------------------------------------------------------------------------
1433 int POSTGRESQL_STORE::SaveMonthStat(const USER_STAT & stat, int month, int year, const std::string & login) const
1434 {
1435 STG_LOCKER lock(&mutex);
1436
1437 return SaveStat(stat, login, year, month);
1438 }
1439
1440 //-----------------------------------------------------------------------------
1441 int POSTGRESQL_STORE::SaveUserServices(uint32_t uid,
1442                                        const std::vector<std::string> & services) const
1443 {
1444 PGresult * result;
1445
1446     {
1447     std::ostringstream query;
1448     query << "DELETE FROM tb_users_services WHERE fk_user = " << uid;
1449
1450     result = PQexec(connection, query.str().c_str());
1451
1452     if (PQresultStatus(result) != PGRES_COMMAND_OK)
1453         {
1454         strError = PQresultErrorMessage(result);
1455         PQclear(result);
1456         printfd(__FILE__, "POSTGRESQL_STORE::SaveUserServices(): '%s'\n", strError.c_str());
1457         return -1;
1458         }
1459
1460     PQclear(result);
1461     }
1462
1463 std::vector<std::string>::const_iterator it;
1464
1465 for (it = services.begin(); it != services.end(); ++it)
1466     {
1467     std::string ename = *it;
1468
1469     if (EscapeString(ename))
1470         {
1471         printfd(__FILE__, "POSTGRESQL_STORE::SaveUserServices(): 'Failed to escape service name'\n");
1472         return -1;
1473         }
1474
1475     std::ostringstream query;
1476     query << "INSERT INTO tb_users_services "
1477                 "(fk_user, fk_service) "
1478              "VALUES "
1479                 "(" << uid << ", "
1480                   "(SELECT pk_service "
1481                    "FROM tb_services "
1482                    "WHERE name = '" << ename << "'))";
1483
1484     result = PQexec(connection, query.str().c_str());
1485
1486     if (PQresultStatus(result) != PGRES_COMMAND_OK)
1487         {
1488         strError = PQresultErrorMessage(result);
1489         PQclear(result);
1490         printfd(__FILE__, "POSTGRESQL_STORE::SaveUserServices(): '%s'\n", strError.c_str());
1491         return -1;
1492         }
1493
1494     PQclear(result);
1495     }
1496
1497 return 0;
1498 }
1499
1500 //-----------------------------------------------------------------------------
1501 int POSTGRESQL_STORE::SaveUserIPs(uint32_t uid,
1502                                   const USER_IPS & ips) const
1503 {
1504 PGresult * result;
1505
1506     {
1507     std::ostringstream query;
1508     query << "DELETE FROM tb_allowed_ip WHERE fk_user = " << uid;
1509
1510     result = PQexec(connection, query.str().c_str());
1511     }
1512
1513 if (PQresultStatus(result) != PGRES_COMMAND_OK)
1514     {
1515     strError = PQresultErrorMessage(result);
1516     PQclear(result);
1517     printfd(__FILE__, "POSTGRESQL_STORE::SaveUserIPs(): '%s'\n", strError.c_str());
1518     return -1;
1519     }
1520
1521 PQclear(result);
1522
1523 for (size_t i = 0; i < ips.Count(); ++i)
1524     {
1525     std::ostringstream query;
1526     query << "INSERT INTO tb_allowed_ip "
1527                 "(fk_user, ip) "
1528              "VALUES "
1529                 "(" << uid << ", CAST('"
1530                     << inet_ntostring(ips[i].ip) << "/"
1531                     << static_cast<int>(ips[i].mask) << "' AS INET))";
1532
1533     result = PQexec(connection, query.str().c_str());
1534
1535     if (PQresultStatus(result) != PGRES_COMMAND_OK)
1536         {
1537         strError = PQresultErrorMessage(result);
1538         PQclear(result);
1539         printfd(__FILE__, "POSTGRESQL_STORE::SaveUserIPs(): '%s'\n", strError.c_str());
1540         return -1;
1541         }
1542
1543     PQclear(result);
1544     }
1545
1546 return 0;
1547 }
1548
1549 //-----------------------------------------------------------------------------
1550 int POSTGRESQL_STORE::SaveUserData(uint32_t uid,
1551                                    const std::vector<std::string> & data) const
1552 {
1553 for (unsigned i = 0; i < data.size(); ++i)
1554     {
1555     std::string edata = data[i];
1556
1557     if (EscapeString(edata))
1558         {
1559         printfd(__FILE__, "POSTGRESQL_STORE::SaveUserData(): 'Failed to escape userdata field'\n");
1560         return -1;
1561         }
1562
1563     PGresult * result;
1564
1565     std::ostringstream query;
1566     query << "SELECT sp_set_user_data("
1567                 << uid << ", "
1568                 << "CAST(" << i << " AS SMALLINT), "
1569                 << "'" << edata << "')";
1570
1571     result = PQexec(connection, query.str().c_str());
1572
1573     if (PQresultStatus(result) != PGRES_TUPLES_OK)
1574         {
1575         strError = PQresultErrorMessage(result);
1576         PQclear(result);
1577         printfd(__FILE__, "POSTGRESQL_STORE::SaveUserData(): '%s'\n", strError.c_str());
1578         return -1;
1579         }
1580
1581     PQclear(result);
1582     }
1583
1584 return 0;
1585 }
1586