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