]> git.stg.codes - stg.git/blob - projects/stargazer/plugins/store/postgresql/postgresql_store_users.cpp
1ab5d0e8c2c806e28974c30065975727efc9bfa4
[stg.git] / projects / 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 conf->ips.Erase();
958 for (int i = 0; i < tuples; ++i)
959     {
960     IP_MASK ipm;
961
962     int ip, mask;
963
964     ip = inet_strington(PQgetvalue(result, i, 0));
965
966     if (str2x(PQgetvalue(result, i, 1), mask))
967         {
968         printfd(__FILE__, "POSTGRESQL_STORE::RestoreUserConf(): 'Failed to fetch mask'\n");
969         continue;
970         }
971
972     ipm.ip = ip;
973     ipm.mask = mask;
974
975     conf->ips.Add(ipm);
976     }
977
978 PQclear(result);
979
980 if (CommitTransaction())
981     {
982     printfd(__FILE__, "POSTGRESQL_STORE::RestoreUserConf(): 'Failed to commit transaction'\n");
983     return -1;
984     }
985
986 return 0;
987 }
988
989 //-----------------------------------------------------------------------------
990 int POSTGRESQL_STORE::WriteUserChgLog(const std::string & login,
991                                     const std::string & admLogin,
992                                     uint32_t admIP,
993                                     const std::string & paramName,
994                                     const std::string & oldValue,
995                                     const std::string & newValue,
996                                     const std::string & message = "") const
997 {
998 STG_LOCKER lock(&mutex);
999
1000 if (PQstatus(connection) != CONNECTION_OK)
1001     {
1002     printfd(__FILE__, "POSTGRESQL_STORE::WriteUserChgLog(): 'Connection lost. Trying to reconnect...'\n", strError.c_str());
1003     if (Reset())
1004         {
1005         strError = "Connection lost";
1006         printfd(__FILE__, "POSTGRESQL_STORE::WriteUserChgLog(): '%s'\n", strError.c_str());
1007         return -1;
1008         }
1009     }
1010
1011 PGresult * result;
1012
1013 if (StartTransaction())
1014     {
1015     printfd(__FILE__, "POSTGRESQL_STORE::WriteUserChgLog(): 'Failed to start transaction'\n");
1016     return -1;
1017     }
1018
1019 std::string elogin(login);
1020 std::string eadminLogin(admLogin);
1021 std::string eparam(paramName);
1022 std::string eold(oldValue);
1023 std::string enew(newValue);
1024 std::string emessage(message);
1025
1026 if (EscapeString(elogin))
1027     {
1028     printfd(__FILE__, "POSTGRESQL_STORE::WriteUserChgLog(): 'Failed to escape login'\n");
1029     if (RollbackTransaction())
1030         {
1031         printfd(__FILE__, "POSTGRESQL_STORE::WriteUserChgLog(): 'Failed to rollback transaction'\n");
1032         }
1033     return -1;
1034     }
1035
1036 if (EscapeString(eadminLogin))
1037     {
1038     printfd(__FILE__, "POSTGRESQL_STORE::WriteUserChgLog(): 'Failed to escape admin's login'\n");
1039     if (RollbackTransaction())
1040         {
1041         printfd(__FILE__, "POSTGRESQL_STORE::WriteUserChgLog(): 'Failed to rollback transaction'\n");
1042         }
1043     return -1;
1044     }
1045
1046 if (EscapeString(eparam))
1047     {
1048     printfd(__FILE__, "POSTGRESQL_STORE::WriteUserChgLog(): 'Failed to escape param's name'\n");
1049     if (RollbackTransaction())
1050         {
1051         printfd(__FILE__, "POSTGRESQL_STORE::WriteUserChgLog(): 'Failed to rollback transaction'\n");
1052         }
1053     return -1;
1054     }
1055
1056 if (EscapeString(eold))
1057     {
1058     printfd(__FILE__, "POSTGRESQL_STORE::WriteUserChgLog(): 'Failed to escape old value'\n");
1059     if (RollbackTransaction())
1060         {
1061         printfd(__FILE__, "POSTGRESQL_STORE::WriteUserChgLog(): 'Failed to rollback transaction'\n");
1062         }
1063     return -1;
1064     }
1065
1066 if (EscapeString(enew))
1067     {
1068     printfd(__FILE__, "POSTGRESQL_STORE::WriteUserChgLog(): 'Failed to escape new value'\n");
1069     if (RollbackTransaction())
1070         {
1071         printfd(__FILE__, "POSTGRESQL_STORE::WriteUserChgLog(): 'Failed to rollback transaction'\n");
1072         }
1073     return -1;
1074     }
1075
1076 std::ostringstream query;
1077 query << "SELECT sp_add_param_log_entry("
1078             "'" << elogin << "', "
1079             "'" << eadminLogin << "', CAST('"
1080             << inet_ntostring(admIP) << "/32' AS INET), "
1081             "'" << eparam << "', "
1082             "CAST('" << formatTime(stgTime) << "' AS TIMESTAMP), "
1083             "'" << eold << "', "
1084             "'" << enew << "', "
1085             "'" << emessage << "')";
1086
1087 result = PQexec(connection, query.str().c_str());
1088
1089 if (PQresultStatus(result) != PGRES_TUPLES_OK)
1090     {
1091     strError = PQresultErrorMessage(result);
1092     PQclear(result);
1093     printfd(__FILE__, "POSTGRESQL_STORE::WriteUserChgLog(): '%s'\n", strError.c_str());
1094     if (RollbackTransaction())
1095         {
1096         printfd(__FILE__, "POSTGRESQL_STORE::WriteUserChgLog(): 'Failed to rollback transaction'\n");
1097         }
1098     return -1;
1099     }
1100
1101 PQclear(result);
1102
1103 if (CommitTransaction())
1104     {
1105     printfd(__FILE__, "POSTGRESQL_STORE::WriteUserChgLog(): 'Failed to commit transaction'\n");
1106     return -1;
1107     }
1108
1109 return 0;
1110 }
1111
1112 //-----------------------------------------------------------------------------
1113 int POSTGRESQL_STORE::WriteUserConnect(const std::string & login, uint32_t ip) const
1114 {
1115 STG_LOCKER lock(&mutex);
1116
1117 if (PQstatus(connection) != CONNECTION_OK)
1118     {
1119     printfd(__FILE__, "POSTGRESQL_STORE::WriteUserConnect(): 'Connection lost. Trying to reconnect...'\n", strError.c_str());
1120     if (Reset())
1121         {
1122         strError = "Connection lost";
1123         printfd(__FILE__, "POSTGRESQL_STORE::WriteUserConnect(): '%s'\n", strError.c_str());
1124         return -1;
1125         }
1126     }
1127
1128 PGresult * result;
1129
1130 if (StartTransaction())
1131     {
1132     printfd(__FILE__, "POSTGRESQL_STORE::WriteUserConnect(): 'Failed to start transaction'\n");
1133     return -1;
1134     }
1135
1136 std::string elogin(login);
1137
1138 if (EscapeString(elogin))
1139     {
1140     printfd(__FILE__, "POSTGRESQL_STORE::WriteUserConnect(): 'Failed to escape login'\n");
1141     if (RollbackTransaction())
1142         {
1143         printfd(__FILE__, "POSTGRESQL_STORE::WriteUserConnect(): 'Failed to rollback transaction'\n");
1144         }
1145     return -1;
1146     }
1147
1148 std::ostringstream query;
1149 if (version < 6)
1150     {
1151     query << "SELECT sp_add_session_log_entry("
1152                  "'" << elogin << "', "
1153                  "CAST('" << formatTime(stgTime) << "' AS TIMESTAMP), "
1154                  "'c', CAST('"
1155                  << inet_ntostring(ip) << "/32' AS INET), 0)";
1156     }
1157 else
1158     {
1159     query << "SELECT sp_add_session_log_entry("
1160                  "'" << elogin << "', "
1161                  "CAST('" << formatTime(stgTime) << "' AS TIMESTAMP), "
1162                  "'c', CAST('"
1163                  << inet_ntostring(ip) << "/32' AS INET), 0, 0, '')";
1164     }
1165
1166 result = PQexec(connection, query.str().c_str());
1167
1168 if (PQresultStatus(result) != PGRES_TUPLES_OK)
1169     {
1170     strError = PQresultErrorMessage(result);
1171     PQclear(result);
1172     printfd(__FILE__, "POSTGRESQL_STORE::WriteUserConnect(): '%s'\n", strError.c_str());
1173     if (RollbackTransaction())
1174         {
1175         printfd(__FILE__, "POSTGRESQL_STORE::WriteUserConnect(): 'Failed to rollback transaction'\n");
1176         }
1177     return -1;
1178     }
1179
1180 PQclear(result);
1181
1182 if (CommitTransaction())
1183     {
1184     printfd(__FILE__, "POSTGRESQL_STORE::WriteUserConnect(): 'Failed to commit transaction'\n");
1185     return -1;
1186     }
1187
1188 return 0;
1189 }
1190
1191 //-----------------------------------------------------------------------------
1192 int POSTGRESQL_STORE::WriteUserDisconnect(const std::string & login,
1193                     const DIR_TRAFF & monthUp,
1194                     const DIR_TRAFF & monthDown,
1195                     const DIR_TRAFF & sessionUp,
1196                     const DIR_TRAFF & sessionDown,
1197                     double cash,
1198                     double freeMb,
1199                     const std::string & reason) const
1200 {
1201 STG_LOCKER lock(&mutex);
1202
1203 if (PQstatus(connection) != CONNECTION_OK)
1204     {
1205     printfd(__FILE__, "POSTGRESQL_STORE::WriteUserDisconnect(): 'Connection lost. Trying to reconnect...'\n", strError.c_str());
1206     if (Reset())
1207         {
1208         strError = "Connection lost";
1209         printfd(__FILE__, "POSTGRESQL_STORE::WriteUserDisconnect(): '%s'\n", strError.c_str());
1210         return -1;
1211         }
1212     }
1213
1214 PGresult * result;
1215
1216 if (StartTransaction())
1217     {
1218     printfd(__FILE__, "POSTGRESQL_STORE::WriteUserDisconnect(): 'Failed to start transaction'\n");
1219     return -1;
1220     }
1221
1222 std::string elogin(login);
1223
1224 if (EscapeString(elogin))
1225     {
1226     printfd(__FILE__, "POSTGRESQL_STORE::WriteUserDisconnect(): 'Failed to escape login'\n");
1227     if (RollbackTransaction())
1228         {
1229         printfd(__FILE__, "POSTGRESQL_STORE::WriteUserDisconnect(): 'Failed to rollback transaction'\n");
1230         }
1231     return -1;
1232     }
1233
1234 std::string ereason(reason);
1235
1236 if (EscapeString(ereason))
1237     {
1238     printfd(__FILE__, "POSTGRESQL_STORE::WriteUserDisconnect(): 'Failed to escape reason'\n");
1239     if (RollbackTransaction())
1240         {
1241         printfd(__FILE__, "POSTGRESQL_STORE::WriteUserDisconnect(): 'Failed to rollback transaction'\n");
1242         }
1243     return -1;
1244     }
1245
1246     {
1247     std::ostringstream query;
1248     if (version < 6)
1249         {
1250         // Old database version - no freeMb logging support
1251         query << "SELECT sp_add_session_log_entry("
1252                     "'" << elogin << "', "
1253                     "CAST('" << formatTime(stgTime) << "' AS TIMESTAMP), "
1254                     "'d', CAST('0.0.0.0/0' AS INET), "
1255                     << cash << ")";
1256         }
1257     else
1258         {
1259         query << "SELECT sp_add_session_log_entry("
1260                     "'" << elogin << "', "
1261                     "CAST('" << formatTime(stgTime) << "' AS TIMESTAMP), "
1262                     "'d', CAST('0.0.0.0/0' AS INET), "
1263                     << cash << ", " << freeMb << ", '" << ereason << "')";
1264         }
1265
1266     result = PQexec(connection, query.str().c_str());
1267     }
1268
1269 if (PQresultStatus(result) != PGRES_TUPLES_OK)
1270     {
1271     strError = PQresultErrorMessage(result);
1272     PQclear(result);
1273     printfd(__FILE__, "POSTGRESQL_STORE::WriteUserDisconnect(): '%s'\n", strError.c_str());
1274     if (RollbackTransaction())
1275         {
1276         printfd(__FILE__, "POSTGRESQL_STORE::WriteUserDisconnect(): 'Failed to rollback transaction'\n");
1277         }
1278     return -1;
1279     }
1280
1281 int tuples = PQntuples(result);
1282
1283 if (tuples != 1)
1284     {
1285     strError = "Failed to fetch session's log ID";
1286     printfd(__FILE__, "POSTGRESQL_STORE::WriteUserDisconnect(): 'Invalid number of tuples. Wanted 1, actulally %d'\n", tuples);
1287     PQclear(result);
1288     if (RollbackTransaction())
1289         {
1290         printfd(__FILE__, "POSTGRESQL_STORE::WriteUserDisconnect(): 'Failed to rollback transaction'\n");
1291         }
1292     return -1;
1293     }
1294
1295 uint32_t lid;
1296
1297 if (str2x(PQgetvalue(result, 0, 0), lid))
1298     {
1299     strError = "Failed to convert string to int";
1300     printfd(__FILE__, "POSTGRESQL_STORE::WriteUserDisconnect(): '%s'\n", strError.c_str());
1301     PQclear(result);
1302     if (RollbackTransaction())
1303         {
1304         printfd(__FILE__, "POSTGRESQL_STORE::WriteUserDisconnect(): 'Failed to rollback transaction'\n");
1305         }
1306     return -1;
1307     }
1308
1309 PQclear(result);
1310
1311 for (int i = 0; i < DIR_NUM; ++i)
1312     {
1313     std::ostringstream query;
1314     query << "INSERT INTO tb_sessions_data "
1315                 "(fk_session_log, "
1316                  "dir_num, "
1317                  "session_upload, "
1318                  "session_download, "
1319                  "month_upload, "
1320                  "month_download)"
1321              "VALUES ("
1322                 << lid << ", "
1323                 << i << ", "
1324                 << sessionUp[i] << ", "
1325                 << sessionDown[i] << ", "
1326                 << monthUp[i] << ", "
1327                 << monthDown[i] << ")";
1328
1329     result = PQexec(connection, query.str().c_str());
1330
1331     if (PQresultStatus(result) != PGRES_COMMAND_OK)
1332         {
1333         strError = PQresultErrorMessage(result);
1334         PQclear(result);
1335         printfd(__FILE__, "POSTGRESQL_STORE::WriteUserDisconnect(): '%s'\n", strError.c_str());
1336         if (RollbackTransaction())
1337             {
1338             printfd(__FILE__, "POSTGRESQL_STORE::WriteUserDisconnect(): 'Failed to rollback transaction'\n");
1339             }
1340         return -1;
1341         }
1342
1343     PQclear(result);
1344     }
1345
1346 if (CommitTransaction())
1347     {
1348     printfd(__FILE__, "POSTGRESQL_STORE::WriteUserDisconnect(): 'Failed to commit transaction'\n");
1349     return -1;
1350     }
1351
1352 return 0;
1353 }
1354
1355 //-----------------------------------------------------------------------------
1356 int POSTGRESQL_STORE::WriteDetailedStat(const std::map<IP_DIR_PAIR, STAT_NODE> & statTree,
1357                                       time_t lastStat,
1358                                       const std::string & login) const
1359 {
1360 STG_LOCKER lock(&mutex);
1361
1362 if (PQstatus(connection) != CONNECTION_OK)
1363     {
1364     printfd(__FILE__, "POSTGRESQL_STORE::WriteDetailedStat(): 'Connection lost. Trying to reconnect...'\n", strError.c_str());
1365     if (Reset())
1366         {
1367         strError = "Connection lost";
1368         printfd(__FILE__, "POSTGRESQL_STORE::WriteDetailedStat(): '%s'\n", strError.c_str());
1369         return -1;
1370         }
1371     }
1372
1373 if (StartTransaction())
1374     {
1375     printfd(__FILE__, "POSTGRESQL_STORE::WriteDetailedStat(): 'Failed to start transaction'\n");
1376     return -1;
1377     }
1378
1379 std::string elogin(login);
1380
1381 if (EscapeString(elogin))
1382     {
1383     printfd(__FILE__, "POSTGRESQL_STORE::WriteDetailedStat(): 'Failed to escape login'\n");
1384     if (RollbackTransaction())
1385         {
1386         printfd(__FILE__, "POSTGRESQL_STORE::WriteDetailedStat(): 'Failed to rollback transaction'\n");
1387         }
1388     return -1;
1389     }
1390
1391 std::map<IP_DIR_PAIR, STAT_NODE>::const_iterator it;
1392 time_t currTime = time(NULL);
1393
1394 for (it = statTree.begin(); it != statTree.end(); ++it)
1395     {
1396     std::ostringstream query;
1397     query << "INSERT INTO tb_detail_stats "
1398                 "(till_time, from_time, fk_user, "
1399                  "dir_num, ip, download, upload, cost) "
1400              "VALUES ("
1401                 "CAST('" << formatTime(currTime) << "' AS TIMESTAMP), "
1402                 "CAST('" << formatTime(lastStat) << "' AS TIMESTAMP), "
1403                 "(SELECT pk_user FROM tb_users WHERE name = '" << elogin << "'), "
1404                 << it->first.dir << ", "
1405                 << "CAST('" << inet_ntostring(it->first.ip) << "' AS INET), "
1406                 << it->second.down << ", "
1407                 << it->second.up << ", "
1408                 << it->second.cash << ")";
1409
1410     PGresult * result = PQexec(connection, query.str().c_str());
1411
1412     if (PQresultStatus(result) != PGRES_COMMAND_OK)
1413         {
1414         strError = PQresultErrorMessage(result);
1415         PQclear(result);
1416         printfd(__FILE__, "POSTGRESQL_STORE::WriteDetailedStat(): '%s'\n", strError.c_str());
1417         if (RollbackTransaction())
1418             {
1419             printfd(__FILE__, "POSTGRESQL_STORE::WriteDetailedStat(): 'Failed to rollback transaction'\n");
1420             }
1421         return -1;
1422         }
1423
1424     PQclear(result);
1425     }
1426
1427 if (CommitTransaction())
1428     {
1429     printfd(__FILE__, "POSTGRESQL_STORE::WriteDetailedStat(): 'Failed to commit transaction'\n");
1430     return -1;
1431     }
1432
1433 return 0;
1434 }
1435
1436 //-----------------------------------------------------------------------------
1437 int POSTGRESQL_STORE::SaveMonthStat(const USER_STAT & stat, int month, int year, const std::string & login) const
1438 {
1439 STG_LOCKER lock(&mutex);
1440
1441 return SaveStat(stat, login, year, month);
1442 }
1443
1444 //-----------------------------------------------------------------------------
1445 int POSTGRESQL_STORE::SaveUserServices(uint32_t uid,
1446                                        const std::vector<std::string> & services) const
1447 {
1448 PGresult * result;
1449
1450     {
1451     std::ostringstream query;
1452     query << "DELETE FROM tb_users_services WHERE fk_user = " << uid;
1453
1454     result = PQexec(connection, query.str().c_str());
1455
1456     if (PQresultStatus(result) != PGRES_COMMAND_OK)
1457         {
1458         strError = PQresultErrorMessage(result);
1459         PQclear(result);
1460         printfd(__FILE__, "POSTGRESQL_STORE::SaveUserServices(): '%s'\n", strError.c_str());
1461         return -1;
1462         }
1463
1464     PQclear(result);
1465     }
1466
1467 std::vector<std::string>::const_iterator it;
1468
1469 for (it = services.begin(); it != services.end(); ++it)
1470     {
1471     std::string ename = *it;
1472
1473     if (EscapeString(ename))
1474         {
1475         printfd(__FILE__, "POSTGRESQL_STORE::SaveUserServices(): 'Failed to escape service name'\n");
1476         return -1;
1477         }
1478
1479     std::ostringstream query;
1480     query << "INSERT INTO tb_users_services "
1481                 "(fk_user, fk_service) "
1482              "VALUES "
1483                 "(" << uid << ", "
1484                   "(SELECT pk_service "
1485                    "FROM tb_services "
1486                    "WHERE name = '" << ename << "'))";
1487
1488     result = PQexec(connection, query.str().c_str());
1489
1490     if (PQresultStatus(result) != PGRES_COMMAND_OK)
1491         {
1492         strError = PQresultErrorMessage(result);
1493         PQclear(result);
1494         printfd(__FILE__, "POSTGRESQL_STORE::SaveUserServices(): '%s'\n", strError.c_str());
1495         return -1;
1496         }
1497
1498     PQclear(result);
1499     }
1500
1501 return 0;
1502 }
1503
1504 //-----------------------------------------------------------------------------
1505 int POSTGRESQL_STORE::SaveUserIPs(uint32_t uid,
1506                                   const USER_IPS & ips) const
1507 {
1508 PGresult * result;
1509
1510     {
1511     std::ostringstream query;
1512     query << "DELETE FROM tb_allowed_ip WHERE fk_user = " << uid;
1513
1514     result = PQexec(connection, query.str().c_str());
1515     }
1516
1517 if (PQresultStatus(result) != PGRES_COMMAND_OK)
1518     {
1519     strError = PQresultErrorMessage(result);
1520     PQclear(result);
1521     printfd(__FILE__, "POSTGRESQL_STORE::SaveUserIPs(): '%s'\n", strError.c_str());
1522     return -1;
1523     }
1524
1525 PQclear(result);
1526
1527 for (size_t i = 0; i < ips.Count(); ++i)
1528     {
1529     std::ostringstream query;
1530     query << "INSERT INTO tb_allowed_ip "
1531                 "(fk_user, ip) "
1532              "VALUES "
1533                 "(" << uid << ", CAST('"
1534                     << inet_ntostring(ips[i].ip) << "/"
1535                     << static_cast<int>(ips[i].mask) << "' AS INET))";
1536
1537     result = PQexec(connection, query.str().c_str());
1538
1539     if (PQresultStatus(result) != PGRES_COMMAND_OK)
1540         {
1541         strError = PQresultErrorMessage(result);
1542         PQclear(result);
1543         printfd(__FILE__, "POSTGRESQL_STORE::SaveUserIPs(): '%s'\n", strError.c_str());
1544         return -1;
1545         }
1546
1547     PQclear(result);
1548     }
1549
1550 return 0;
1551 }
1552
1553 //-----------------------------------------------------------------------------
1554 int POSTGRESQL_STORE::SaveUserData(uint32_t uid,
1555                                    const std::vector<std::string> & data) const
1556 {
1557 for (unsigned i = 0; i < data.size(); ++i)
1558     {
1559     std::string edata = data[i];
1560
1561     if (EscapeString(edata))
1562         {
1563         printfd(__FILE__, "POSTGRESQL_STORE::SaveUserData(): 'Failed to escape userdata field'\n");
1564         return -1;
1565         }
1566
1567     PGresult * result;
1568
1569     std::ostringstream query;
1570     query << "SELECT sp_set_user_data("
1571                 << uid << ", "
1572                 << "CAST(" << i << " AS SMALLINT), "
1573                 << "'" << edata << "')";
1574
1575     result = PQexec(connection, query.str().c_str());
1576
1577     if (PQresultStatus(result) != PGRES_TUPLES_OK)
1578         {
1579         strError = PQresultErrorMessage(result);
1580         PQclear(result);
1581         printfd(__FILE__, "POSTGRESQL_STORE::SaveUserData(): '%s'\n", strError.c_str());
1582         return -1;
1583         }
1584
1585     PQclear(result);
1586     }
1587
1588 return 0;
1589 }
1590