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