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