]> git.stg.codes - stg.git/blob - projects/stargazer/plugins/store/mysql/mysql_store.cpp
Show config only on demand.
[stg.git] / projects / stargazer / plugins / store / mysql / mysql_store.cpp
1 #include <sys/time.h>
2 #include <cerrno>
3 #include <cstdio>
4 #include <cstdlib>
5 #include <algorithm>
6
7 #include <mysql.h>
8 #include <errmsg.h>
9
10 #include "stg/user_ips.h"
11 #include "stg/user_conf.h"
12 #include "stg/user_stat.h"
13 #include "stg/blowfish.h"
14 #include "stg/plugin_creator.h"
15 #include "stg/logger.h"
16 #include "mysql_store.h"
17
18 #define adm_enc_passwd "cjeifY8m3"
19
20 namespace
21 {
22 char qbuf[4096];
23
24 const int pt_mega = 1024 * 1024;
25 const std::string badSyms = "'`";
26 const char repSym = '\"';
27 const int RepitTimes = 3;
28
29 template <typename T>
30 int GetInt(const std::string & str, T * val, T defaultVal = T())
31 {
32     char *res;
33     
34     *val = static_cast<T>(strtoll(str.c_str(), &res, 10));
35     
36     if (*res != 0) 
37     {
38         *val = defaultVal; //Error!
39         return EINVAL;
40     }
41
42     return 0;
43 }
44
45 int GetDouble(const std::string & str, double * val, double defaultVal)
46 {
47     char *res;
48     
49     *val = strtod(str.c_str(), &res);
50     
51     if (*res != 0) 
52     {
53         *val = defaultVal; //Error!
54         return EINVAL;
55     }
56
57     return 0;
58 }
59
60 int GetTime(const std::string & str, time_t * val, time_t defaultVal)
61 {
62     char *res;
63     
64     *val = strtol(str.c_str(), &res, 10);
65     
66     if (*res != 0) 
67     {
68         *val = defaultVal; //Error!
69         return EINVAL;
70     }
71
72     return 0;
73 }
74
75 //-----------------------------------------------------------------------------
76 std::string ReplaceStr(std::string source, const std::string & symlist, const char chgsym)
77 {
78     std::string::size_type pos=0;
79
80     while( (pos = source.find_first_of(symlist,pos)) != std::string::npos)
81         source.replace(pos, 1,1, chgsym);
82
83     return source;
84 }
85
86 int GetULongLongInt(const std::string & str, uint64_t * val, uint64_t defaultVal)
87 {
88     char *res;
89     
90     *val = strtoull(str.c_str(), &res, 10);
91     
92     if (*res != 0) 
93     {
94         *val = defaultVal; //Error!
95         return EINVAL;
96     }
97
98     return 0;
99
100
101 PLUGIN_CREATOR<MYSQL_STORE> msc;
102 }
103
104 extern "C" STORE * GetStore();
105 //-----------------------------------------------------------------------------
106 //-----------------------------------------------------------------------------
107 //-----------------------------------------------------------------------------
108 STORE * GetStore()
109 {
110 return msc.GetPlugin();
111 }
112 //-----------------------------------------------------------------------------
113 MYSQL_STORE_SETTINGS::MYSQL_STORE_SETTINGS()
114     : settings(NULL),
115       errorStr(),
116       dbUser(),
117       dbPass(),
118       dbName(),
119       dbHost()
120 {
121 }
122 //-----------------------------------------------------------------------------
123 int MYSQL_STORE_SETTINGS::ParseParam(const std::vector<PARAM_VALUE> & moduleParams, 
124                         const std::string & name, std::string & result)
125 {
126 PARAM_VALUE pv;
127 pv.param = name;
128 std::vector<PARAM_VALUE>::const_iterator pvi;
129 pvi = find(moduleParams.begin(), moduleParams.end(), pv);
130 if (pvi == moduleParams.end())
131     {
132     errorStr = "Parameter \'" + name + "\' not found.";
133     return -1;
134     }
135     
136 result = pvi->value[0];
137
138 return 0;
139 }
140 //-----------------------------------------------------------------------------
141 int MYSQL_STORE_SETTINGS::ParseSettings(const MODULE_SETTINGS & s)
142 {
143 if (ParseParam(s.moduleParams, "user", dbUser) < 0 &&
144     ParseParam(s.moduleParams, "dbuser", dbUser) < 0)
145     return -1;
146 if (ParseParam(s.moduleParams, "password", dbPass) < 0 &&
147     ParseParam(s.moduleParams, "rootdbpass", dbPass) < 0)
148     return -1;
149 if (ParseParam(s.moduleParams, "database", dbName) < 0 &&
150     ParseParam(s.moduleParams, "dbname", dbName) < 0)
151     return -1;
152 if (ParseParam(s.moduleParams, "server", dbHost) < 0 &&
153     ParseParam(s.moduleParams, "dbhost", dbHost) < 0)
154     return -1;
155
156 return 0;
157 }
158 //-----------------------------------------------------------------------------
159 //-----------------------------------------------------------------------------
160 //-----------------------------------------------------------------------------
161 MYSQL_STORE::MYSQL_STORE()
162     : errorStr(),
163       version("mysql_store v.0.67"),
164       storeSettings(),
165       settings(),
166       schemaVersion(0),
167       logger(GetPluginLogger(GetStgLogger(), "store_mysql"))
168 {
169 }
170 //-----------------------------------------------------------------------------
171 int    MYSQL_STORE::MysqlQuery(const char* sQuery,MYSQL * sock) const
172 {
173     int ret;
174
175     if( (ret = mysql_query(sock,sQuery)) )
176     {
177         for(int i=0; i<RepitTimes; i++)
178         {
179             if( (ret = mysql_query(sock,sQuery)) )
180                 ;//need to send error result
181             else
182                 return 0;
183         }
184     }
185     
186     return ret;
187 }
188 //-----------------------------------------------------------------------------
189
190 //-----------------------------------------------------------------------------
191 int MYSQL_STORE::ParseSettings()
192 {
193 int ret = storeSettings.ParseSettings(settings);
194 MYSQL mysql;
195 mysql_init(&mysql);
196 if (ret)
197     errorStr = storeSettings.GetStrError();
198 else
199 {
200     if(storeSettings.GetDBPassword().length() == 0)
201     {
202         errorStr = "Database password must be not empty. Please read Manual.";
203         return -1;
204     }
205     MYSQL * sock;
206     if (!(sock = mysql_real_connect(&mysql,storeSettings.GetDBHost().c_str(),
207             storeSettings.GetDBUser().c_str(),storeSettings.GetDBPassword().c_str(),
208             0,0,NULL,0)))
209         {
210             errorStr = "Couldn't connect to mysql engine! With error:\n";
211             errorStr += mysql_error(&mysql);
212             mysql_close(sock);
213             ret = -1;
214         }
215     else
216     {
217          if(mysql_select_db(sock, storeSettings.GetDBName().c_str()))
218          {
219              std::string res = "CREATE DATABASE " + storeSettings.GetDBName();
220             
221             if(MysqlQuery(res.c_str(),sock))
222             {
223                 errorStr = "Couldn't create database! With error:\n";
224                 errorStr += mysql_error(sock);
225                 mysql_close(sock);
226                 ret = -1;
227             }
228             else
229             {
230                  if(mysql_select_db(sock, storeSettings.GetDBName().c_str()))
231                  {
232                     errorStr = "Couldn't select database! With error:\n";
233                     errorStr += mysql_error(sock);
234                     mysql_close(sock);
235                     ret = -1;
236                  }
237                  ret = CheckAllTables(sock);
238             }
239         }
240         else
241         {
242             ret = CheckAllTables(sock);
243         }
244         if (!ret)
245         {
246             logger("MYSQL_STORE: Current DB schema version: %d", schemaVersion);
247             MakeUpdates(sock);
248         }
249         mysql_close(sock);
250     }
251 }
252 return ret;
253 }
254 //-----------------------------------------------------------------------------
255 bool MYSQL_STORE::IsTablePresent(const std::string & str,MYSQL * sock)
256 {
257 MYSQL_RES* result;
258
259 if (!(result=mysql_list_tables(sock,str.c_str() )))
260 {
261     errorStr = "Couldn't get tables list With error:\n";
262     errorStr += mysql_error(sock);
263     mysql_close(sock);
264     return -1;
265 }
266
267 my_ulonglong num_rows =  mysql_num_rows(result);
268
269 if(result)
270     mysql_free_result(result);
271
272 return num_rows == 1;
273 }
274 //-----------------------------------------------------------------------------
275 int MYSQL_STORE::CheckAllTables(MYSQL * sock)
276 {
277 //info-------------------------------------------------------------------------
278 if(!IsTablePresent("info",sock))
279 {
280     sprintf(qbuf,"CREATE TABLE info (version INTEGER NOT NULL)");
281
282     if(MysqlQuery(qbuf,sock))
283         {
284         errorStr = "Couldn't create info table With error:\n";
285         errorStr += mysql_error(sock);
286         mysql_close(sock);
287         return -1;
288         }
289
290     sprintf(qbuf,"INSERT INTO info SET version=0");
291
292     if(MysqlQuery(qbuf,sock))
293         {
294         errorStr = "Couldn't write default version. With error:\n";
295         errorStr += mysql_error(sock);
296         mysql_close(sock);
297         return -1;
298         }
299     schemaVersion = 0;
300 }
301 else
302 {
303     std::vector<std::string> info;
304     if (GetAllParams(&info, "info", "version"))
305         schemaVersion = 0;
306     else
307     {
308         if (info.empty())
309             schemaVersion = 0;
310         else
311             GetInt(info.front(), &schemaVersion, 0);
312     }
313 }
314 //admins-----------------------------------------------------------------------
315 if(!IsTablePresent("admins",sock))
316 {
317     sprintf(qbuf,"CREATE TABLE admins (login VARCHAR(40) DEFAULT '' PRIMARY KEY,"\
318         "password VARCHAR(150) DEFAULT '*',ChgConf TINYINT DEFAULT 0,"\
319         "ChgPassword TINYINT DEFAULT 0,ChgStat TINYINT DEFAULT 0,"\
320         "ChgCash TINYINT DEFAULT 0,UsrAddDel TINYINT DEFAULT 0,"\
321         "ChgTariff TINYINT DEFAULT 0,ChgAdmin TINYINT DEFAULT 0)");
322     
323     if(MysqlQuery(qbuf,sock))
324     {
325         errorStr = "Couldn't create admin table list With error:\n";
326         errorStr += mysql_error(sock);
327         mysql_close(sock);
328         return -1;
329     }
330
331     sprintf(qbuf,"INSERT INTO admins SET login='admin',"\
332         "password='geahonjehjfofnhammefahbbbfbmpkmkmmefahbbbfbmpkmkmmefahbbbfbmpkmkaa',"\
333         "ChgConf=1,ChgPassword=1,ChgStat=1,ChgCash=1,UsrAddDel=1,ChgTariff=1,ChgAdmin=1");
334     
335     if(MysqlQuery(qbuf,sock))
336     {
337         errorStr = "Couldn't create default admin. With error:\n";
338         errorStr += mysql_error(sock);
339         mysql_close(sock);
340         return -1;
341     }
342 }
343
344 //tariffs-----------------------------------------------------------------------
345 std::string param, res;
346 if(!IsTablePresent("tariffs",sock))
347 {
348     res = "CREATE TABLE tariffs (name VARCHAR(40) DEFAULT '' PRIMARY KEY,";
349         
350     for (int i = 0; i < DIR_NUM; i++)
351         {
352         strprintf(&param, " PriceDayA%d DOUBLE DEFAULT 0.0,", i); 
353         res += param;
354     
355         strprintf(&param, " PriceDayB%d DOUBLE DEFAULT 0.0,", i);
356         res += param;
357             
358         strprintf(&param, " PriceNightA%d DOUBLE DEFAULT 0.0,", i);
359         res += param;
360     
361         strprintf(&param, " PriceNightB%d DOUBLE DEFAULT 0.0,", i);
362         res += param;
363             
364         strprintf(&param, " Threshold%d INT DEFAULT 0,", i);
365         res += param;
366     
367         strprintf(&param, " Time%d VARCHAR(15) DEFAULT '0:0-0:0',", i);
368         res += param;
369     
370         strprintf(&param, " NoDiscount%d INT DEFAULT 0,", i);
371         res += param;
372     
373         strprintf(&param, " SinglePrice%d INT DEFAULT 0,", i);
374         res += param;
375         }
376     
377     res += "PassiveCost DOUBLE DEFAULT 0.0, Fee DOUBLE DEFAULT 0.0,"
378         "Free DOUBLE DEFAULT 0.0, TraffType VARCHAR(10) DEFAULT '',"
379         "period VARCHAR(32) NOT NULL DEFAULT 'month')";
380     
381     if(MysqlQuery(res.c_str(),sock))
382     {
383         errorStr = "Couldn't create tariffs table list With error:\n";
384         errorStr += mysql_error(sock);
385         mysql_close(sock);
386         return -1;
387     }
388
389     res = "INSERT INTO tariffs SET name='tariff',";
390         
391     for (int i = 0; i < DIR_NUM; i++)
392         {
393         strprintf(&param, " NoDiscount%d=1,", i);
394         res += param;
395     
396         strprintf(&param, " Threshold%d=0,", i);
397         res += param;
398     
399         strprintf(&param, " Time%d='0:0-0:0',", i);
400         res += param;
401     
402         if(i != 0 && i != 1)
403         {
404             strprintf(&param, " SinglePrice%d=0,", i);
405             res += param;        
406         }
407     
408         if(i != 1)
409         {
410             strprintf(&param, " PriceDayA%d=0.0,", i); 
411             res += param;        
412         }
413         if(i != 1)
414         {
415             strprintf(&param, " PriceDayB%d=0.0,", i);        
416             res += param;    
417         }
418     
419         if(i != 0)
420         {
421             strprintf(&param, " PriceNightA%d=0.0,", i); 
422             res += param;        
423         }
424         if(i != 0)
425         {
426             strprintf(&param, " PriceNightB%d=0.0,", i);        
427             res += param;    
428         }
429         }
430     
431     res += "PassiveCost=0.0, Fee=10.0, Free=0,"\
432         "SinglePrice0=1, SinglePrice1=1,PriceDayA1=0.75,PriceDayB1=0.75,"\
433         "PriceNightA0=1.0,PriceNightB0=1.0,TraffType='up+down',period='month'";
434     
435     if(MysqlQuery(res.c_str(),sock))
436     {
437         errorStr = "Couldn't create default tariff. With error:\n";
438         errorStr += mysql_error(sock);
439         mysql_close(sock);
440         return -1;
441     }
442
443     sprintf(qbuf,"UPDATE info SET version=1");
444
445     if(MysqlQuery(qbuf,sock))
446     {
447         errorStr = "Couldn't write default version. With error:\n";
448         errorStr += mysql_error(sock);
449         mysql_close(sock);
450         return -1;
451     }
452     schemaVersion = 1;
453 }
454
455 //users-----------------------------------------------------------------------
456 if(!IsTablePresent("users",sock))
457 {
458     res = "CREATE TABLE users (login VARCHAR(50) NOT NULL DEFAULT '' PRIMARY KEY, Password VARCHAR(150) NOT NULL DEFAULT '*',"\
459         "Passive INT(3) DEFAULT 0,Down INT(3) DEFAULT 0,DisabledDetailStat INT(3) DEFAULT 0,AlwaysOnline INT(3) DEFAULT 0,Tariff VARCHAR(40) NOT NULL DEFAULT '',"\
460         "Address VARCHAR(254) NOT NULL DEFAULT '',Phone VARCHAR(128) NOT NULL DEFAULT '',Email VARCHAR(50) NOT NULL DEFAULT '',"\
461         "Note TEXT NOT NULL,RealName VARCHAR(254) NOT NULL DEFAULT '',StgGroup VARCHAR(40) NOT NULL DEFAULT '',"\
462         "Credit DOUBLE DEFAULT 0, TariffChange VARCHAR(40) NOT NULL DEFAULT '',";
463     
464     for (int i = 0; i < USERDATA_NUM; i++)
465         {
466         strprintf(&param, " Userdata%d VARCHAR(254) NOT NULL,", i);
467         res += param;
468         }
469     
470     param = " CreditExpire INT(11) DEFAULT 0,";
471     res += param;
472     
473     strprintf(&param, " IP VARCHAR(254) DEFAULT '*',");
474     res += param;
475     
476     for (int i = 0; i < DIR_NUM; i++)
477         {
478         strprintf(&param, " D%d BIGINT(30) DEFAULT 0,", i);
479         res += param;
480     
481         strprintf(&param, " U%d BIGINT(30) DEFAULT 0,", i);
482         res += param;
483         }
484     
485     strprintf(&param, "Cash DOUBLE DEFAULT 0,FreeMb DOUBLE DEFAULT 0,LastCashAdd DOUBLE DEFAULT 0,"\
486         "LastCashAddTime INT(11) DEFAULT 0,PassiveTime INT(11) DEFAULT 0,LastActivityTime INT(11) DEFAULT 0,"\
487         "NAS VARCHAR(17) NOT NULL, INDEX (AlwaysOnline), INDEX (IP), INDEX (Address),"\
488         " INDEX (Tariff),INDEX (Phone),INDEX (Email),INDEX (RealName))");
489     res += param;
490         
491     if(MysqlQuery(res.c_str(),sock))
492     {
493         errorStr = "Couldn't create users table list With error:\n";
494         errorStr += mysql_error(sock);
495         errorStr += "\n\n" + res;
496         mysql_close(sock);
497         return -1;
498     }
499
500     res = "INSERT INTO users SET login='test',Address='',AlwaysOnline=0,"\
501         "Credit=0.0,CreditExpire=0,Down=0,Email='',DisabledDetailStat=0,"\
502         "StgGroup='',IP='192.168.1.1',Note='',Passive=0,Password='123456',"\
503         "Phone='', RealName='',Tariff='tariff',TariffChange='',NAS='',";
504     
505     for (int i = 0; i < USERDATA_NUM; i++)
506         {
507         strprintf(&param, " Userdata%d='',", i);
508         res += param;
509         }
510     
511     for (int i = 0; i < DIR_NUM; i++)
512         {
513         strprintf(&param, " D%d=0,", i);
514         res += param;
515     
516         strprintf(&param, " U%d=0,", i);
517         res += param;
518         }
519     
520     res += "Cash=10.0,FreeMb=0.0,LastActivityTime=0,LastCashAdd=0,"\
521         "LastCashAddTime=0, PassiveTime=0";
522         
523     if(MysqlQuery(res.c_str(),sock))
524     {
525         errorStr = "Couldn't create default user. With error:\n";
526         errorStr += mysql_error(sock);
527         mysql_close(sock);
528         return -1;
529     }
530 }
531 /*
532 //logs-----------------------------------------------------------------------
533 if(!IsTablePresent("logs"))
534 {
535     sprintf(qbuf,"CREATE TABLE logs (unid INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, login VARCHAR(40),text TEXT)");
536     
537     if(MysqlQuery(qbuf))
538     {
539         errorStr = "Couldn't create admin table list With error:\n";
540         errorStr += mysql_error(sock);
541         return -1;
542     }
543 }
544 */
545 //messages---------------------------------------------------------------------
546 if(!IsTablePresent("messages",sock))
547 {
548     sprintf(qbuf,"CREATE TABLE messages (login VARCHAR(40) DEFAULT '', id BIGINT, "\
549             "type INT, lastSendTime INT, creationTime INT, showTime INT,"\
550             "stgRepeat INT, repeatPeriod INT, text TEXT)");
551     
552     if(MysqlQuery(qbuf,sock))
553     {
554         errorStr = "Couldn't create messages table. With error:\n";
555         errorStr += mysql_error(sock);
556         mysql_close(sock);
557         return -1;
558     }
559 }
560
561 //month_stat-------------------------------------------------------------------
562 if(!IsTablePresent("stat",sock))
563 {
564     res = "CREATE TABLE stat (login VARCHAR(50), month TINYINT, year SMALLINT,";
565     
566     for (int i = 0; i < DIR_NUM; i++)
567         {
568         strprintf(&param, " U%d BIGINT,", i); 
569         res += param;
570             
571         strprintf(&param, " D%d BIGINT,", i); 
572         res += param;
573         }
574         
575     res += " cash DOUBLE, INDEX (login))";
576     
577     if(MysqlQuery(res.c_str(),sock))
578     {
579         errorStr = "Couldn't create stat table. With error:\n";
580         errorStr += mysql_error(sock);
581         mysql_close(sock);
582         return -1;
583     }
584 }
585
586 return 0;
587 }
588 //-----------------------------------------------------------------------------
589 int MYSQL_STORE::MakeUpdates(MYSQL * sock)
590 {
591 if (schemaVersion  < 1)
592     {
593     if (MysqlQuery("ALTER TABLE tariffs ADD period VARCHAR(32) NOT NULL DEFAULT 'month'", sock))
594         {
595         errorStr = "Couldn't update tariffs table to version 1. With error:\n";
596         errorStr += mysql_error(sock);
597         mysql_close(sock);
598         return -1;
599         }
600     if (MysqlQuery("UPDATE info SET version = 1", sock))
601         {
602         errorStr = "Couldn't update DB schema version to 1. With error:\n";
603         errorStr += mysql_error(sock);
604         mysql_close(sock);
605         return -1;
606         }
607     schemaVersion = 1;
608     logger("MYSQL_STORE: Updated DB schema to version %d", schemaVersion);
609     }
610 return 0;
611 }
612 //-----------------------------------------------------------------------------
613
614 int MYSQL_STORE::GetAllParams(std::vector<std::string> * ParamList, 
615                             const std::string & table, const std::string & name) const
616 {
617 MYSQL_RES *res;
618 MYSQL_ROW row;
619 MYSQL * sock=NULL;
620 my_ulonglong num, i;
621     
622 ParamList->clear();
623     
624 sprintf(qbuf,"SELECT %s FROM %s", name.c_str(), table.c_str());
625     
626 if(MysqlGetQuery(qbuf,sock))
627 {
628     errorStr = "Couldn't GetAllParams Query for: ";
629     errorStr += name + " - " + table + "\n";
630     errorStr += mysql_error(sock);
631     mysql_close(sock);
632     return -1;
633 }
634
635 if (!(res=mysql_store_result(sock)))
636 {
637     errorStr = "Couldn't GetAllParams Results for: ";
638     errorStr += name + " - " + table + "\n";
639     errorStr += mysql_error(sock);
640     return -1;
641 }
642
643 num = mysql_num_rows(res);
644
645 for(i = 0; i < num; i++)
646 {
647     row = mysql_fetch_row(res);    
648     ParamList->push_back(row[0]);
649 }
650
651 mysql_free_result(res);
652 mysql_close(sock);
653
654 return 0;
655 }
656
657 //-----------------------------------------------------------------------------
658 int MYSQL_STORE::GetUsersList(std::vector<std::string> * usersList) const
659 {
660 if(GetAllParams(usersList, "users", "login"))
661     return -1;
662
663 return 0;
664 }
665 //-----------------------------------------------------------------------------
666 int MYSQL_STORE::GetAdminsList(std::vector<std::string> * adminsList) const
667 {
668 if(GetAllParams(adminsList, "admins", "login"))
669     return -1;
670
671 return 0;
672 }
673 //-----------------------------------------------------------------------------
674 int MYSQL_STORE::GetTariffsList(std::vector<std::string> * tariffsList) const
675 {
676 if(GetAllParams(tariffsList, "tariffs", "name"))
677     return -1;
678
679 return 0;
680 }
681 //-----------------------------------------------------------------------------
682 int MYSQL_STORE::AddUser(const std::string & login) const
683 {
684 std::string query = "INSERT INTO users SET login='" + login + "',Note='',NAS=''";
685
686 for (int i = 0; i < USERDATA_NUM; i++)
687     query += ",Userdata" + x2str(i) + "=''";
688
689 if(MysqlSetQuery(query.c_str()))
690 {
691     errorStr = "Couldn't add user:\n";
692     //errorStr += mysql_error(sock);
693     return -1;
694 }
695
696 return 0;
697 }
698 //-----------------------------------------------------------------------------
699 int MYSQL_STORE::DelUser(const std::string & login) const
700 {
701 sprintf(qbuf,"DELETE FROM users WHERE login='%s' LIMIT 1", login.c_str());
702     
703 if(MysqlSetQuery(qbuf))
704 {
705     errorStr = "Couldn't delete user:\n";
706     //errorStr += mysql_error(sock);
707     return -1;
708 }
709
710 return 0;
711 }
712 //-----------------------------------------------------------------------------
713 int MYSQL_STORE::RestoreUserConf(USER_CONF * conf, const std::string & login) const
714 {
715 MYSQL_RES *res;
716 MYSQL_ROW row;
717 MYSQL * sock;
718 std::string query;
719
720 query = "SELECT login, Password, Passive, Down, DisabledDetailStat, \
721          AlwaysOnline, Tariff, Address, Phone, Email, Note, \
722          RealName, StgGroup, Credit, TariffChange, ";
723
724 for (int i = 0; i < USERDATA_NUM; i++)
725 {
726     sprintf(qbuf, "Userdata%d, ", i);
727     query += qbuf;
728 }
729
730 query += "CreditExpire, IP FROM users WHERE login='";
731 query += login + "' LIMIT 1";
732
733 //sprintf(qbuf,"SELECT * FROM users WHERE login='%s' LIMIT 1", login.c_str());
734     
735 if(MysqlGetQuery(query.c_str(),sock))
736 {
737     errorStr = "Couldn't restore Tariff(on query):\n";
738     errorStr += mysql_error(sock);
739     mysql_close(sock);
740     return -1;
741 }
742
743 if (!(res=mysql_store_result(sock)))
744 {
745     errorStr = "Couldn't restore Tariff(on getting result):\n";
746     errorStr += mysql_error(sock);
747     mysql_close(sock);
748     return -1;
749 }
750
751 if (mysql_num_rows(res) != 1)
752 {
753     errorStr = "User not found";
754     mysql_close(sock);
755     return -1;
756 }
757
758 row = mysql_fetch_row(res);
759
760 conf->password = row[1];
761
762 if (conf->password.empty())
763     {
764     mysql_free_result(res);
765     errorStr = "User \'" + login + "\' password is blank.";
766     mysql_close(sock);
767     return -1;
768     }
769
770 if (GetInt(row[2],&conf->passive) != 0)
771     {
772     mysql_free_result(res);
773     errorStr = "User \'" + login + "\' data not read. Parameter Passive.";
774     mysql_close(sock);
775     return -1;
776     }
777
778 if (GetInt(row[3], &conf->disabled) != 0)
779     {
780     mysql_free_result(res);
781     errorStr = "User \'" + login + "\' data not read. Parameter Down.";
782     mysql_close(sock);
783     return -1;
784     }
785
786 if (GetInt(row[4], &conf->disabledDetailStat) != 0)
787     {
788     mysql_free_result(res);
789     errorStr = "User \'" + login + "\' data not read. Parameter DisabledDetailStat.";
790     mysql_close(sock);
791     return -1;
792     }
793
794 if (GetInt(row[5], &conf->alwaysOnline) != 0)
795     {
796     mysql_free_result(res);
797     errorStr = "User \'" + login + "\' data not read. Parameter AlwaysOnline.";
798     mysql_close(sock);
799     return -1;
800     }
801
802 conf->tariffName = row[6];
803
804 if (conf->tariffName.empty()) 
805     {
806     mysql_free_result(res);
807     errorStr = "User \'" + login + "\' tariff is blank.";
808     mysql_close(sock);
809     return -1;
810     }
811
812 conf->address = row[7];
813 conf->phone = row[8];
814 conf->email = row[9];
815 conf->note = row[10];
816 conf->realName = row[11];
817 conf->group = row[12];
818
819 if (GetDouble(row[13], &conf->credit, 0) != 0)
820     {
821     mysql_free_result(res);
822     errorStr = "User \'" + login + "\' data not read. Parameter Credit.";
823     mysql_close(sock);
824     return -1;
825     }
826
827 conf->nextTariff = row[14];
828
829 for (int i = 0; i < USERDATA_NUM; i++)
830     {
831     conf->userdata[i] = row[15+i];
832     }
833
834 GetTime(row[15+USERDATA_NUM], &conf->creditExpire, 0);
835     
836 std::string ipStr = row[16+USERDATA_NUM];
837 USER_IPS i;
838 try
839     {
840     i = StrToIPS(ipStr);
841     }
842 catch (const std::string & s)
843     {
844     mysql_free_result(res);
845     errorStr = "User \'" + login + "\' data not read. Parameter IP address. " + s;
846     mysql_close(sock);
847     return -1;
848     }
849 conf->ips = i;
850
851 mysql_free_result(res);
852 mysql_close(sock);
853
854 return 0;
855 }
856 //-----------------------------------------------------------------------------
857 int MYSQL_STORE::RestoreUserStat(USER_STAT * stat, const std::string & login) const
858 {
859 MYSQL_RES *res;
860 MYSQL_ROW row;
861 MYSQL * sock;
862
863 std::string query;
864
865 query = "SELECT ";
866
867 for (int i = 0; i < DIR_NUM; i++)
868 {
869     sprintf(qbuf, "D%d, U%d, ", i, i);
870     query += qbuf;
871 }
872
873 query += "Cash, FreeMb, LastCashAdd, LastCashAddTime, PassiveTime, LastActivityTime \
874           FROM users WHERE login = '";
875 query += login + "'";
876
877 //sprintf(qbuf,"SELECT * FROM users WHERE login='%s' LIMIT 1", login.c_str());
878     
879 if(MysqlGetQuery(query.c_str() ,sock))
880 {
881     errorStr = "Couldn't restore UserStat(on query):\n";
882     errorStr += mysql_error(sock);
883     mysql_close(sock);
884     return -1;
885 }
886
887 if (!(res=mysql_store_result(sock)))
888 {
889     errorStr = "Couldn't restore UserStat(on getting result):\n";
890     errorStr += mysql_error(sock);
891     mysql_close(sock);
892     return -1;
893 }
894
895 row = mysql_fetch_row(res);
896
897 unsigned int startPos=0;
898
899 char s[22];
900
901 for (int i = 0; i < DIR_NUM; i++)
902     {
903     uint64_t traff;
904     sprintf(s, "D%d", i);
905     if (GetULongLongInt(row[startPos+i*2], &traff, 0) != 0)
906         {
907         mysql_free_result(res);
908         errorStr = "User \'" + login + "\' stat not read. Parameter " + std::string(s);
909         mysql_close(sock);
910         return -1;
911         }
912     stat->monthDown[i] = traff;
913
914     sprintf(s, "U%d", i);
915     if (GetULongLongInt(row[startPos+i*2+1], &traff, 0) != 0)
916         {
917         mysql_free_result(res);
918         errorStr =   "User \'" + login + "\' stat not read. Parameter " + std::string(s);
919         mysql_close(sock);
920         return -1;
921         }
922     stat->monthUp[i] = traff;
923     }//for
924
925 startPos += (2*DIR_NUM);
926
927 if (GetDouble(row[startPos], &stat->cash, 0) != 0)
928     {
929     mysql_free_result(res);
930     errorStr =   "User \'" + login + "\' stat not read. Parameter Cash";
931     mysql_close(sock);
932     return -1;
933     }
934
935 if (GetDouble(row[startPos+1],&stat->freeMb, 0) != 0)
936     {
937     mysql_free_result(res);
938     errorStr =   "User \'" + login + "\' stat not read. Parameter FreeMb";
939     mysql_close(sock);
940     return -1;
941     }
942
943 if (GetDouble(row[startPos+2], &stat->lastCashAdd, 0) != 0)
944     {
945     mysql_free_result(res);
946     errorStr =   "User \'" + login + "\' stat not read. Parameter LastCashAdd";
947     mysql_close(sock);
948     return -1;
949     }
950
951 if (GetTime(row[startPos+3], &stat->lastCashAddTime, 0) != 0)
952     {
953     mysql_free_result(res);
954     errorStr =   "User \'" + login + "\' stat not read. Parameter LastCashAddTime";
955     mysql_close(sock);
956     return -1;
957     }
958
959 if (GetTime(row[startPos+4], &stat->passiveTime, 0) != 0)
960     {
961     mysql_free_result(res);
962     errorStr =   "User \'" + login + "\' stat not read. Parameter PassiveTime";
963     mysql_close(sock);
964     return -1;
965     }
966
967 if (GetTime(row[startPos+5], &stat->lastActivityTime, 0) != 0)
968     {
969     mysql_free_result(res);
970     errorStr =   "User \'" + login + "\' stat not read. Parameter LastActivityTime";
971     mysql_close(sock);
972     return -1;
973     }
974
975 mysql_free_result(res);
976 mysql_close(sock);
977 return 0;
978 }
979 //-----------------------------------------------------------------------------
980 int MYSQL_STORE::SaveUserConf(const USER_CONF & conf, const std::string & login) const
981 {
982 std::string param;
983 std::string res;
984
985 strprintf(&res,"UPDATE users SET Password='%s', Passive=%d, Down=%d, DisabledDetailStat = %d, "\
986     "AlwaysOnline=%d, Tariff='%s', Address='%s', Phone='%s', Email='%s', "\
987     "Note='%s', RealName='%s', StgGroup='%s', Credit=%f, TariffChange='%s', ", 
988     conf.password.c_str(),
989     conf.passive,
990     conf.disabled,
991     conf.disabledDetailStat,
992     conf.alwaysOnline,
993     conf.tariffName.c_str(),
994     (ReplaceStr(conf.address,badSyms,repSym)).c_str(),
995     (ReplaceStr(conf.phone,badSyms,repSym)).c_str(),
996     (ReplaceStr(conf.email,badSyms,repSym)).c_str(),
997     (ReplaceStr(conf.note,badSyms,repSym)).c_str(),
998     (ReplaceStr(conf.realName,badSyms,repSym)).c_str(),
999     (ReplaceStr(conf.group,badSyms,repSym)).c_str(),
1000     conf.credit,
1001     conf.nextTariff.c_str()
1002     );
1003
1004 for (int i = 0; i < USERDATA_NUM; i++)
1005     {
1006     strprintf(&param, " Userdata%d='%s',", i, 
1007         (ReplaceStr(conf.userdata[i],badSyms,repSym)).c_str());
1008     res += param;
1009     }
1010     
1011 strprintf(&param, " CreditExpire=%d,", conf.creditExpire);
1012 res += param;
1013
1014 std::ostringstream ipStr;
1015 ipStr << conf.ips;
1016
1017 strprintf(&param, " IP='%s'", ipStr.str().c_str());
1018 res += param;
1019
1020 strprintf(&param, " WHERE login='%s' LIMIT 1", login.c_str());
1021 res += param;
1022
1023 if(MysqlSetQuery(res.c_str()))
1024 {
1025     errorStr = "Couldn't save user conf:\n";
1026     //errorStr += mysql_error(sock);
1027     return -1;
1028 }
1029
1030 return 0;
1031 }
1032 //-----------------------------------------------------------------------------
1033 int MYSQL_STORE::SaveUserStat(const USER_STAT & stat, const std::string & login) const
1034 {
1035 std::string param;
1036 std::string res;
1037
1038 res = "UPDATE users SET";
1039
1040 for (int i = 0; i < DIR_NUM; i++)
1041     {
1042     strprintf(&param, " D%d=%lld,", i, stat.monthDown[i]);
1043     res += param;
1044
1045     strprintf(&param, " U%d=%lld,", i, stat.monthUp[i]);
1046     res += param;
1047     }
1048
1049 strprintf(&param, " Cash=%f, FreeMb=%f, LastCashAdd=%f, LastCashAddTime=%d,"\
1050     " PassiveTime=%d, LastActivityTime=%d", 
1051     stat.cash,
1052     stat.freeMb,
1053     stat.lastCashAdd,
1054     stat.lastCashAddTime,
1055     stat.passiveTime,
1056     stat.lastActivityTime
1057     );
1058 res += param;
1059
1060 strprintf(&param, " WHERE login='%s' LIMIT 1", login.c_str());
1061 res += param;
1062
1063 if(MysqlSetQuery(res.c_str()))
1064 {
1065     errorStr = "Couldn't save user stat:\n";
1066 //    errorStr += mysql_error(sock);
1067     return -1;
1068 }
1069
1070 return 0;
1071 }
1072 //-----------------------------------------------------------------------------
1073 int MYSQL_STORE::WriteLogString(const std::string & str, const std::string & login) const
1074 {
1075 std::string res, tempStr;
1076 time_t t;
1077 tm * lt;
1078
1079 t = time(NULL);
1080 lt = localtime(&t);
1081
1082 MYSQL_RES* result;
1083 MYSQL * sock;
1084 strprintf(&tempStr, "logs_%02d_%4d", lt->tm_mon+1, lt->tm_year+1900);
1085 if (!(sock=MysqlConnect())){
1086     errorStr = "Couldn't connect to Server";
1087     return -1;
1088 }
1089 if (!(result=mysql_list_tables(sock,tempStr.c_str() )))
1090 {
1091     errorStr = "Couldn't get table " + tempStr + ":\n";
1092     errorStr += mysql_error(sock);
1093     mysql_close(sock);
1094     return -1;
1095 }
1096
1097 my_ulonglong num_rows =  mysql_num_rows(result);
1098
1099 mysql_free_result(result);
1100
1101 if (num_rows < 1)
1102 {
1103     sprintf(qbuf,"CREATE TABLE logs_%02d_%4d (unid INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, login VARCHAR(40),text TEXT)",
1104     lt->tm_mon+1, lt->tm_year+1900);
1105     
1106     if(MysqlQuery(qbuf,sock))
1107     {
1108         errorStr = "Couldn't create WriteDetailedStat table:\n";
1109         errorStr += mysql_error(sock);
1110         mysql_close(sock);
1111         return -1;
1112     }
1113 }
1114
1115 strprintf(&res, "%s -- %s",LogDate(t), str.c_str());
1116
1117 std::string send;
1118
1119 strprintf(&send,"INSERT INTO logs_%02d_%4d SET login='%s', text='%s'",
1120         lt->tm_mon+1, lt->tm_year+1900,
1121     login.c_str(), (ReplaceStr(res,badSyms,repSym)).c_str());
1122
1123 if(MysqlQuery(send.c_str(),sock))
1124 {
1125     errorStr = "Couldn't write log string:\n";
1126     errorStr += mysql_error(sock);
1127     mysql_close(sock);
1128     return -1;
1129 }
1130 mysql_close(sock);
1131 return 0;
1132
1133 }
1134 //-----------------------------------------------------------------------------
1135 int MYSQL_STORE::WriteUserChgLog(const std::string & login,
1136                                  const std::string & admLogin,
1137                                  uint32_t       admIP,
1138                                  const std::string & paramName,
1139                                  const std::string & oldValue,
1140                                  const std::string & newValue,
1141                                  const std::string & message) const
1142 {
1143 std::string userLogMsg = "Admin \'" + admLogin + "\', " + inet_ntostring(admIP) + ": \'"
1144     + paramName + "\' parameter changed from \'" + oldValue +
1145     "\' to \'" + newValue + "\'. " + message;
1146
1147 return WriteLogString(userLogMsg, login);
1148 }
1149 //-----------------------------------------------------------------------------
1150 int MYSQL_STORE::WriteUserConnect(const std::string & login, uint32_t ip) const
1151 {
1152 std::string logStr = "Connect, " + inet_ntostring(ip);
1153 return WriteLogString(logStr, login);
1154 }
1155 //-----------------------------------------------------------------------------
1156 int MYSQL_STORE::WriteUserDisconnect(const std::string & login,
1157                                      const DIR_TRAFF & up,
1158                                      const DIR_TRAFF & down,
1159                                      const DIR_TRAFF & sessionUp,
1160                                      const DIR_TRAFF & sessionDown,
1161                                      double cash,
1162                                      double /*freeMb*/,
1163                                      const std::string & /*reason*/) const
1164 {
1165 std::string logStr = "Disconnect, ";
1166 std::ostringstream sssu;
1167 std::ostringstream sssd;
1168 std::ostringstream ssmu;
1169 std::ostringstream ssmd;
1170 std::ostringstream sscash;
1171
1172 ssmu << up;
1173 ssmd << down;
1174
1175 sssu << sessionUp;
1176 sssd << sessionDown;
1177
1178 sscash << cash;
1179
1180 logStr += " session upload: \'";
1181 logStr += sssu.str();
1182 logStr += "\' session download: \'";
1183 logStr += sssd.str();
1184 logStr += "\' month upload: \'";
1185 logStr += ssmu.str();
1186 logStr += "\' month download: \'";
1187 logStr += ssmd.str();
1188 logStr += "\' cash: \'";
1189 logStr += sscash.str();
1190 logStr += "\'";
1191
1192 return WriteLogString(logStr, login);
1193 }
1194 //-----------------------------------------------------------------------------
1195 int MYSQL_STORE::SaveMonthStat(const USER_STAT & stat, int month, int year, 
1196                                 const std::string & login) const
1197 {
1198 std::string param, res;
1199
1200 strprintf(&res, "INSERT INTO stat SET login='%s', month=%d, year=%d,", 
1201     login.c_str(), month+1, year+1900);
1202     
1203 for (int i = 0; i < DIR_NUM; i++)
1204     {
1205     strprintf(&param, " U%d=%lld,", i, stat.monthUp[i]); 
1206     res += param;
1207
1208     strprintf(&param, " D%d=%lld,", i, stat.monthDown[i]);        
1209     res += param;
1210     }
1211     
1212 strprintf(&param, " cash=%f", stat.cash);        
1213 res += param;
1214
1215 if(MysqlSetQuery(res.c_str()))
1216 {
1217     errorStr = "Couldn't SaveMonthStat:\n";
1218     //errorStr += mysql_error(sock);
1219     return -1;
1220 }
1221
1222 return 0;
1223 }
1224 //-----------------------------------------------------------------------------*/
1225 int MYSQL_STORE::AddAdmin(const std::string & login) const
1226 {
1227 sprintf(qbuf,"INSERT INTO admins SET login='%s'", login.c_str());
1228     
1229 if(MysqlSetQuery(qbuf))
1230 {
1231     errorStr = "Couldn't add admin:\n";
1232     //errorStr += mysql_error(sock);
1233     return -1;
1234 }
1235
1236 return 0;
1237 }
1238 //-----------------------------------------------------------------------------*/
1239 int MYSQL_STORE::DelAdmin(const std::string & login) const
1240 {
1241 sprintf(qbuf,"DELETE FROM admins where login='%s' LIMIT 1", login.c_str());
1242     
1243 if(MysqlSetQuery(qbuf))
1244 {
1245     errorStr = "Couldn't delete admin:\n";
1246     //errorStr += mysql_error(sock);
1247     return -1;
1248 }
1249
1250 return 0;
1251 }
1252 //-----------------------------------------------------------------------------*/
1253 int MYSQL_STORE::SaveAdmin(const ADMIN_CONF & ac) const
1254 {
1255 char passwordE[2 * ADM_PASSWD_LEN + 2];
1256 char pass[ADM_PASSWD_LEN + 1];
1257 char adminPass[ADM_PASSWD_LEN + 1];
1258
1259 memset(pass, 0, sizeof(pass));
1260 memset(adminPass, 0, sizeof(adminPass));
1261
1262 BLOWFISH_CTX ctx;
1263 InitContext(adm_enc_passwd, strlen(adm_enc_passwd), &ctx);
1264
1265 strncpy(adminPass, ac.password.c_str(), ADM_PASSWD_LEN);
1266 adminPass[ADM_PASSWD_LEN - 1] = 0;
1267
1268 for (int i = 0; i < ADM_PASSWD_LEN/8; i++)
1269     {
1270     EncryptBlock(pass + 8*i, adminPass + 8*i, &ctx);
1271     }
1272
1273 pass[ADM_PASSWD_LEN - 1] = 0;
1274 Encode12(passwordE, pass, ADM_PASSWD_LEN);
1275
1276 sprintf(qbuf,"UPDATE admins SET password='%s', ChgConf=%d, ChgPassword=%d, "\
1277     "ChgStat=%d, ChgCash=%d, UsrAddDel=%d, ChgTariff=%d, ChgAdmin=%d "\
1278     "WHERE login='%s' LIMIT 1", 
1279     passwordE,
1280     ac.priv.userConf,
1281     ac.priv.userPasswd,
1282     ac.priv.userStat,
1283     ac.priv.userCash,
1284     ac.priv.userAddDel,
1285     ac.priv.tariffChg,
1286     ac.priv.adminChg,
1287     ac.login.c_str()
1288     );
1289
1290 if(MysqlSetQuery(qbuf))
1291 {
1292     errorStr = "Couldn't save admin:\n";
1293     //errorStr += mysql_error(sock);
1294     return -1;
1295 }
1296
1297 return 0;
1298 }
1299 //-----------------------------------------------------------------------------
1300 int MYSQL_STORE::RestoreAdmin(ADMIN_CONF * ac, const std::string & login) const
1301 {
1302 char pass[ADM_PASSWD_LEN + 1];
1303 char password[ADM_PASSWD_LEN + 1];
1304 char passwordE[2*ADM_PASSWD_LEN + 2];
1305 BLOWFISH_CTX ctx;
1306
1307 memset(password, 0, sizeof(password));
1308
1309 std::string p;
1310 MYSQL_RES *res;
1311 MYSQL_ROW row;
1312 MYSQL * sock;
1313 sprintf(qbuf,"SELECT * FROM admins WHERE login='%s' LIMIT 1", login.c_str());
1314     
1315 if(MysqlGetQuery(qbuf,sock))
1316 {
1317     errorStr = "Couldn't restore admin:\n";
1318     errorStr += mysql_error(sock);
1319     mysql_close(sock);
1320     return -1;
1321 }
1322
1323 if (!(res=mysql_store_result(sock)))
1324 {
1325     errorStr = "Couldn't restore admin:\n";
1326     errorStr += mysql_error(sock);
1327     mysql_close(sock);
1328     return -1;
1329 }
1330
1331 if ( mysql_num_rows(res) == 0)
1332 {
1333     mysql_free_result(res);
1334     errorStr = "Couldn't restore admin as couldn't found him in table.\n";
1335     mysql_close(sock);
1336     return -1;
1337 }
1338   
1339 row = mysql_fetch_row(res);
1340
1341 p = row[1];
1342
1343 if(p.length() == 0)
1344 {
1345     mysql_free_result(res);
1346     errorStr = "Error in parameter password";
1347     mysql_close(sock);
1348     return -1;
1349 }
1350
1351 memset(passwordE, 0, sizeof(passwordE));
1352 strncpy(passwordE, p.c_str(), 2*ADM_PASSWD_LEN);
1353
1354 memset(pass, 0, sizeof(pass));
1355
1356 if (passwordE[0] != 0)
1357     {
1358     Decode21(pass, passwordE);
1359     InitContext(adm_enc_passwd, strlen(adm_enc_passwd), &ctx);
1360
1361     for (int i = 0; i < ADM_PASSWD_LEN/8; i++)
1362         {
1363         DecryptBlock(password + 8*i, pass + 8*i, &ctx);
1364         }
1365     }
1366 else
1367     {
1368     password[0] = 0;
1369     }
1370
1371 ac->password = password;
1372
1373 uint16_t a;
1374
1375 if (GetInt(row[2], &a) == 0) 
1376     ac->priv.userConf = a;
1377 else
1378     {
1379     mysql_free_result(res);
1380     errorStr = "Error in parameter ChgConf";
1381     mysql_close(sock);
1382     return -1;
1383     }
1384
1385 if (GetInt(row[3], &a) == 0) 
1386     ac->priv.userPasswd = a;
1387 else
1388     {
1389     mysql_free_result(res);
1390     errorStr = "Error in parameter ChgPassword";
1391     mysql_close(sock);
1392     return -1;
1393     }
1394
1395 if (GetInt(row[4], &a) == 0) 
1396     ac->priv.userStat = a;
1397 else
1398     {
1399     mysql_free_result(res);
1400     errorStr = "Error in parameter ChgStat";
1401     mysql_close(sock);
1402     return -1;
1403     }
1404
1405 if (GetInt(row[5], &a) == 0) 
1406     ac->priv.userCash = a;
1407 else
1408     {
1409     mysql_free_result(res);
1410     errorStr = "Error in parameter ChgCash";
1411     mysql_close(sock);
1412     return -1;
1413     }
1414
1415 if (GetInt(row[6], &a) == 0) 
1416     ac->priv.userAddDel = a;
1417 else
1418     {
1419     mysql_free_result(res);
1420     errorStr = "Error in parameter UsrAddDel";
1421     mysql_close(sock);
1422     return -1;
1423     }
1424
1425 if (GetInt(row[7], &a) == 0) 
1426     ac->priv.tariffChg = a;
1427 else
1428     {
1429     mysql_free_result(res);
1430     errorStr = "Error in parameter ChgTariff";
1431     mysql_close(sock);
1432     return -1;
1433     }
1434
1435 if (GetInt(row[8], &a) == 0) 
1436     ac->priv.adminChg = a;
1437 else
1438     {
1439     mysql_free_result(res);
1440     errorStr = "Error in parameter ChgAdmin";
1441     mysql_close(sock);
1442     return -1;
1443     }
1444
1445 mysql_free_result(res);
1446 mysql_close(sock);
1447 return 0;
1448 }
1449 //-----------------------------------------------------------------------------
1450 int MYSQL_STORE::AddTariff(const std::string & name) const
1451 {
1452 sprintf(qbuf,"INSERT INTO tariffs SET name='%s'", name.c_str());
1453     
1454 if(MysqlSetQuery(qbuf))
1455 {
1456     errorStr = "Couldn't add tariff:\n";
1457 //    errorStr += mysql_error(sock);
1458     return -1;
1459 }
1460
1461 return 0;
1462 }
1463 //-----------------------------------------------------------------------------
1464 int MYSQL_STORE::DelTariff(const std::string & name) const
1465 {
1466 sprintf(qbuf,"DELETE FROM tariffs WHERE name='%s' LIMIT 1", name.c_str());
1467     
1468 if(MysqlSetQuery(qbuf))
1469 {
1470     errorStr = "Couldn't delete tariff: ";
1471 //    errorStr += mysql_error(sock);
1472     return -1;
1473 }
1474
1475 return 0;
1476 }
1477 //-----------------------------------------------------------------------------
1478 int MYSQL_STORE::RestoreTariff(TARIFF_DATA * td, const std::string & tariffName) const
1479 {
1480 MYSQL_RES *res;
1481 MYSQL_ROW row;
1482 MYSQL * sock;
1483 sprintf(qbuf,"SELECT * FROM tariffs WHERE name='%s' LIMIT 1", tariffName.c_str());
1484     
1485 if(MysqlGetQuery(qbuf,sock))
1486 {
1487     errorStr = "Couldn't restore Tariff:\n";
1488     errorStr += mysql_error(sock);
1489     mysql_close(sock);
1490     return -1;
1491 }
1492
1493 if (!(res=mysql_store_result(sock)))
1494 {
1495     errorStr = "Couldn't restore Tariff:\n";
1496     errorStr += mysql_error(sock);
1497     mysql_close(sock);
1498     return -1;
1499 }
1500
1501 std::string str;
1502 td->tariffConf.name = tariffName;
1503
1504 row = mysql_fetch_row(res);
1505
1506 std::string param;
1507 for (int i = 0; i<DIR_NUM; i++)
1508     {
1509     strprintf(&param, "Time%d", i);
1510     str = row[6+i*8];
1511     if (str.length() == 0)
1512         {
1513         mysql_free_result(res);
1514         errorStr = "Cannot read tariff " + tariffName + ". Parameter " + param;
1515         mysql_close(sock);
1516         return -1;
1517         }
1518
1519     ParseTariffTimeStr(str.c_str(), 
1520                        td->dirPrice[i].hDay, 
1521                        td->dirPrice[i].mDay, 
1522                        td->dirPrice[i].hNight, 
1523                        td->dirPrice[i].mNight);
1524
1525     strprintf(&param, "PriceDayA%d", i);
1526     if (GetDouble(row[1+i*8], &td->dirPrice[i].priceDayA, 0.0) < 0)
1527         {
1528         mysql_free_result(res);
1529         errorStr = "Cannot read tariff " + tariffName + ". Parameter " + param;
1530         mysql_close(sock);
1531         return -1;
1532         }
1533     td->dirPrice[i].priceDayA /= (1024*1024);
1534
1535     strprintf(&param, "PriceDayB%d", i);
1536     if (GetDouble(row[2+i*8], &td->dirPrice[i].priceDayB, 0.0) < 0)
1537         {
1538         mysql_free_result(res);
1539         errorStr = "Cannot read tariff " + tariffName + ". Parameter " + param;
1540         mysql_close(sock);
1541         return -1;
1542         }
1543     td->dirPrice[i].priceDayB /= (1024*1024);
1544
1545     strprintf(&param, "PriceNightA%d", i);
1546     if (GetDouble(row[3+i*8], &td->dirPrice[i].priceNightA, 0.0) < 0)
1547         {
1548         mysql_free_result(res);
1549         errorStr = "Cannot read tariff " + tariffName + ". Parameter " + param;
1550         mysql_close(sock);
1551         return -1;
1552         }
1553     td->dirPrice[i].priceNightA /= (1024*1024);
1554
1555     strprintf(&param, "PriceNightB%d", i);
1556     if (GetDouble(row[4+i*8], &td->dirPrice[i].priceNightB, 0.0) < 0)
1557         {
1558         mysql_free_result(res);
1559         errorStr = "Cannot read tariff " + tariffName + ". Parameter " + param;
1560         mysql_close(sock);
1561         return -1;
1562         }
1563     td->dirPrice[i].priceNightB /= (1024*1024);
1564
1565     strprintf(&param, "Threshold%d", i);
1566     if (GetInt(row[5+i*8], &td->dirPrice[i].threshold) < 0)
1567         {
1568         mysql_free_result(res);
1569         errorStr = "Cannot read tariff " + tariffName + ". Parameter " + param;
1570         mysql_close(sock);
1571         return -1;
1572         }
1573
1574     strprintf(&param, "SinglePrice%d", i);
1575     if (GetInt(row[8+i*8], &td->dirPrice[i].singlePrice) < 0)
1576         {
1577         mysql_free_result(res);
1578         errorStr = "Cannot read tariff " + tariffName + ". Parameter " + param;
1579         mysql_close(sock);
1580         return -1;
1581         }
1582
1583     strprintf(&param, "NoDiscount%d", i);
1584     if (GetInt(row[7+i*8], &td->dirPrice[i].noDiscount) < 0)
1585         {
1586         mysql_free_result(res);
1587         errorStr = "Cannot read tariff " + tariffName + ". Parameter " + param;
1588         mysql_close(sock);
1589         return -1;
1590         }
1591     }//main for
1592
1593 if (GetDouble(row[2+8*DIR_NUM], &td->tariffConf.fee, 0.0) < 0)
1594     {
1595     mysql_free_result(res);
1596     errorStr = "Cannot read tariff " + tariffName + ". Parameter Fee";
1597     mysql_close(sock);
1598     return -1;
1599     }
1600
1601 if (GetDouble(row[3+8*DIR_NUM], &td->tariffConf.free, 0.0) < 0)
1602     {
1603     mysql_free_result(res);
1604     errorStr = "Cannot read tariff " + tariffName + ". Parameter Free";
1605     mysql_close(sock);
1606     return -1;
1607     }
1608
1609 if (GetDouble(row[1+8*DIR_NUM], &td->tariffConf.passiveCost, 0.0) < 0)
1610     {
1611     mysql_free_result(res);
1612     errorStr = "Cannot read tariff " + tariffName + ". Parameter PassiveCost";
1613     mysql_close(sock);
1614     return -1;
1615     }
1616
1617     str = row[4+8*DIR_NUM];
1618     param = "TraffType";
1619     
1620     if (str.length() == 0)
1621         {
1622         mysql_free_result(res);
1623         errorStr = "Cannot read tariff " + tariffName + ". Parameter " + param;
1624         mysql_close(sock);
1625         return -1;
1626         }
1627
1628 td->tariffConf.traffType = TARIFF::StringToTraffType(str);
1629
1630 if (schemaVersion > 0)
1631 {
1632     str = row[5+8*DIR_NUM];
1633     param = "Period";
1634
1635     if (str.length() == 0)
1636         {
1637         mysql_free_result(res);
1638         errorStr = "Cannot read tariff " + tariffName + ". Parameter " + param;
1639         mysql_close(sock);
1640         return -1;
1641         }
1642
1643     td->tariffConf.period = TARIFF::StringToPeriod(str);
1644     }
1645 else
1646     {
1647     td->tariffConf.period = TARIFF::MONTH;
1648     }
1649
1650 mysql_free_result(res);
1651 mysql_close(sock);
1652 return 0;
1653 }
1654 //-----------------------------------------------------------------------------
1655 int MYSQL_STORE::SaveTariff(const TARIFF_DATA & td, const std::string & tariffName) const
1656 {
1657 std::string param;
1658
1659 std::string res="UPDATE tariffs SET";
1660
1661 for (int i = 0; i < DIR_NUM; i++)
1662     {
1663     strprintf(&param, " PriceDayA%d=%f,", i, 
1664         td.dirPrice[i].priceDayA * pt_mega);
1665     res += param;
1666
1667     strprintf(&param, " PriceDayB%d=%f,", i, 
1668         td.dirPrice[i].priceDayB * pt_mega);        
1669     res += param;
1670         
1671     strprintf(&param, " PriceNightA%d=%f,", i,
1672         td.dirPrice[i].priceNightA * pt_mega);
1673     res += param;
1674
1675     strprintf(&param, " PriceNightB%d=%f,", i, 
1676         td.dirPrice[i].priceNightB * pt_mega);
1677     res += param;
1678         
1679     strprintf(&param, " Threshold%d=%d,", i, 
1680         td.dirPrice[i].threshold);
1681     res += param;
1682
1683     std::string s;
1684     strprintf(&param, " Time%d", i);
1685
1686     strprintf(&s, "%0d:%0d-%0d:%0d", 
1687             td.dirPrice[i].hDay,
1688             td.dirPrice[i].mDay,
1689             td.dirPrice[i].hNight,
1690             td.dirPrice[i].mNight);
1691
1692     res += (param + "='" + s + "',");
1693
1694     strprintf(&param, " NoDiscount%d=%d,", i, 
1695         td.dirPrice[i].noDiscount);
1696     res += param;
1697
1698     strprintf(&param, " SinglePrice%d=%d,", i, 
1699         td.dirPrice[i].singlePrice);
1700     res += param;
1701     }
1702
1703 strprintf(&param, " PassiveCost=%f,", td.tariffConf.passiveCost);
1704 res += param;
1705
1706 strprintf(&param, " Fee=%f,", td.tariffConf.fee);
1707 res += param;
1708
1709 strprintf(&param, " Free=%f,", td.tariffConf.free);
1710 res += param;
1711
1712 res += " TraffType='" + TARIFF::TraffTypeToString(td.tariffConf.traffType) + "'";
1713
1714 if (schemaVersion > 0)
1715     res += ", Period='" + TARIFF::PeriodToString(td.tariffConf.period) + "'";
1716
1717 strprintf(&param, " WHERE name='%s' LIMIT 1", tariffName.c_str());
1718 res += param;
1719
1720 if(MysqlSetQuery(res.c_str()))
1721 {
1722     errorStr = "Couldn't save tariff:\n";
1723     //errorStr += mysql_error(sock);
1724     return -1;
1725 }
1726
1727 return 0;
1728 }
1729 //-----------------------------------------------------------------------------
1730 int MYSQL_STORE::WriteDetailedStat(const std::map<IP_DIR_PAIR, STAT_NODE> & statTree, 
1731                                    time_t lastStat, 
1732                                    const std::string & login) const
1733 {
1734 std::string res, stTime, endTime, tempStr;
1735 time_t t;
1736 tm * lt;
1737
1738 t = time(NULL);
1739 lt = localtime(&t);
1740
1741 if (lt->tm_hour == 0 && lt->tm_min <= 5)
1742     {
1743         t -= 3600 * 24;
1744         lt = localtime(&t);
1745     }
1746
1747 MYSQL_RES* result;
1748 MYSQL * sock;
1749 strprintf(&tempStr, "detailstat_%02d_%4d", lt->tm_mon+1, lt->tm_year+1900);
1750
1751 if (!(sock=MysqlConnect())){
1752     mysql_close(sock);
1753     return -1;
1754 }
1755
1756 if (!(result=mysql_list_tables(sock,tempStr.c_str() )))
1757 {
1758     errorStr = "Couldn't get table " + tempStr + ":\n";
1759     errorStr += mysql_error(sock);
1760     mysql_close(sock);
1761     return -1;
1762 }
1763
1764 my_ulonglong num_rows =  mysql_num_rows(result);
1765
1766 mysql_free_result(result);
1767
1768 if (num_rows < 1)
1769 {
1770     sprintf(qbuf,"CREATE TABLE detailstat_%02d_%4d (login VARCHAR(40) DEFAULT '',"\
1771         "day TINYINT DEFAULT 0,startTime TIME,endTime TIME,"\
1772         "IP VARCHAR(17) DEFAULT '',dir INT DEFAULT 0,"\
1773         "down BIGINT DEFAULT 0,up BIGINT DEFAULT 0, cash DOUBLE DEFAULT 0.0, INDEX (login), INDEX(dir), INDEX(day), INDEX(IP))",
1774     lt->tm_mon+1, lt->tm_year+1900);
1775     
1776     if(MysqlQuery(qbuf,sock))
1777     {
1778         errorStr = "Couldn't create WriteDetailedStat table:\n";
1779         errorStr += mysql_error(sock);
1780         mysql_close(sock);
1781         return -1;
1782     }
1783 }
1784
1785 struct tm * lt1;
1786 struct tm * lt2;
1787
1788 lt1 = localtime(&lastStat);
1789
1790 int h1, m1, s1;
1791 int h2, m2, s2;
1792
1793 h1 = lt1->tm_hour;
1794 m1 = lt1->tm_min;
1795 s1 = lt1->tm_sec;
1796
1797 lt2 = localtime(&t);
1798
1799 h2 = lt2->tm_hour;
1800 m2 = lt2->tm_min;
1801 s2 = lt2->tm_sec;
1802     
1803 strprintf(&stTime, "%02d:%02d:%02d", h1, m1, s1);
1804 strprintf(&endTime, "%02d:%02d:%02d", h2, m2, s2);
1805
1806 strprintf(&res,"INSERT INTO detailstat_%02d_%4d SET login='%s',"\
1807     "day=%d,startTime='%s',endTime='%s',", 
1808     lt->tm_mon+1, lt->tm_year+1900,
1809     login.c_str(),
1810     lt->tm_mday,
1811     stTime.c_str(),
1812     endTime.c_str()
1813     );
1814
1815 std::map<IP_DIR_PAIR, STAT_NODE>::const_iterator stIter;
1816 stIter = statTree.begin();
1817
1818 while (stIter != statTree.end())
1819     {
1820         strprintf(&tempStr,"IP='%s', dir=%d, down=%lld, up=%lld, cash=%f", 
1821                 inet_ntostring(stIter->first.ip).c_str(),
1822                 stIter->first.dir, 
1823                 stIter->second.down, 
1824                 stIter->second.up, 
1825                 stIter->second.cash
1826             );
1827     
1828         if( MysqlQuery((res+tempStr).c_str(),sock) )
1829         {
1830             errorStr = "Couldn't insert data in WriteDetailedStat:\n";
1831             errorStr += mysql_error(sock);
1832             mysql_close(sock);
1833             return -1;
1834         }
1835
1836         result=mysql_store_result(sock);
1837         if(result)
1838             mysql_free_result(result);
1839
1840         ++stIter;
1841     }
1842 mysql_close(sock);
1843 return 0;
1844 }
1845 //-----------------------------------------------------------------------------
1846 int MYSQL_STORE::AddMessage(STG_MSG * msg, const std::string & login) const
1847 {
1848 struct timeval tv;
1849
1850 gettimeofday(&tv, NULL);
1851
1852 msg->header.id = static_cast<uint64_t>(tv.tv_sec) * 1000000 + static_cast<uint64_t>(tv.tv_usec);
1853
1854 sprintf(qbuf,"INSERT INTO messages SET login='%s', id=%lld", 
1855     login.c_str(),
1856     static_cast<long long>(msg->header.id)
1857     );
1858     
1859 if(MysqlSetQuery(qbuf))
1860 {
1861     errorStr = "Couldn't add message:\n";
1862     //errorStr += mysql_error(sock);
1863     return -1;
1864 }
1865
1866 return EditMessage(*msg, login);
1867 }
1868 //-----------------------------------------------------------------------------
1869 int MYSQL_STORE::EditMessage(const STG_MSG & msg, const std::string & login) const
1870 {
1871 std::string res;
1872
1873 strprintf(&res,"UPDATE messages SET type=%d, lastSendTime=%u, creationTime=%u, "\
1874     "showTime=%u, stgRepeat=%d, repeatPeriod=%u, text='%s' "\
1875     "WHERE login='%s' AND id=%lld LIMIT 1", 
1876     msg.header.type,
1877     msg.header.lastSendTime,
1878     msg.header.creationTime,
1879     msg.header.showTime,
1880     msg.header.repeat,
1881     msg.header.repeatPeriod,
1882     (ReplaceStr(msg.text,badSyms,repSym)).c_str(),
1883     login.c_str(),
1884     msg.header.id
1885     );
1886
1887 if(MysqlSetQuery(res.c_str()))
1888 {
1889     errorStr = "Couldn't edit message:\n";
1890     //errorStr += mysql_error(sock);
1891     return -1;
1892 }
1893
1894 return 0;
1895 }
1896 //-----------------------------------------------------------------------------
1897 int MYSQL_STORE::GetMessage(uint64_t id, STG_MSG * msg, const std::string & login) const
1898 {
1899 MYSQL_RES *res;
1900 MYSQL_ROW row;
1901 MYSQL * sock;
1902
1903 sprintf(qbuf,"SELECT * FROM messages WHERE login='%s' AND id=%llu LIMIT 1",
1904         login.c_str(), static_cast<unsigned long long>(id));
1905     
1906 if(MysqlGetQuery(qbuf,sock))
1907 {
1908     errorStr = "Couldn't GetMessage:\n";
1909     errorStr += mysql_error(sock);
1910     mysql_close(sock);
1911     return -1;
1912 }
1913
1914 if (!(res=mysql_store_result(sock)))
1915 {
1916     errorStr = "Couldn't GetMessage:\n";
1917     errorStr += mysql_error(sock);
1918     mysql_close(sock);
1919     return -1;
1920 }
1921
1922 row = mysql_fetch_row(res);
1923
1924 if(row[2]&&str2x(row[2], msg->header.type))
1925 {
1926     mysql_free_result(res);
1927     errorStr = "Invalid value in message header for user: " + login;
1928     mysql_close(sock);
1929     return -1;
1930 }
1931
1932 if(row[3] && str2x(row[3], msg->header.lastSendTime))
1933 {
1934     mysql_free_result(res);
1935     errorStr = "Invalid value in message header for user: " + login;
1936     mysql_close(sock);
1937     return -1;
1938 }
1939
1940 if(row[4] && str2x(row[4], msg->header.creationTime))
1941 {
1942     mysql_free_result(res);
1943     errorStr = "Invalid value in message header for user: " + login;
1944     mysql_close(sock);
1945     return -1;
1946 }
1947
1948 if(row[5] && str2x(row[5], msg->header.showTime))
1949 {
1950     mysql_free_result(res);
1951     errorStr = "Invalid value in message header for user: " + login;
1952     mysql_close(sock);
1953     return -1;
1954 }
1955
1956 if(row[6] && str2x(row[6], msg->header.repeat))
1957 {
1958     mysql_free_result(res);
1959     errorStr = "Invalid value in message header for user: " + login;
1960     mysql_close(sock);
1961     return -1;
1962 }
1963
1964 if(row[7] && str2x(row[7], msg->header.repeatPeriod))
1965 {
1966     mysql_free_result(res);
1967     errorStr = "Invalid value in message header for user: " + login;
1968     mysql_close(sock);
1969     return -1;
1970 }
1971
1972 msg->header.id = id;
1973 msg->text = row[8];
1974
1975 mysql_free_result(res);
1976 mysql_close(sock);
1977 return 0;
1978 }
1979 //-----------------------------------------------------------------------------
1980 int MYSQL_STORE::DelMessage(uint64_t id, const std::string & login) const
1981 {
1982 sprintf(qbuf,"DELETE FROM messages WHERE login='%s' AND id=%lld LIMIT 1", 
1983         login.c_str(), static_cast<long long>(id));
1984     
1985 if(MysqlSetQuery(qbuf))
1986 {
1987     errorStr = "Couldn't delete Message:\n";
1988     //errorStr += mysql_error(sock);
1989     return -1;
1990 }
1991
1992 return 0;
1993 }
1994 //-----------------------------------------------------------------------------
1995 int MYSQL_STORE::GetMessageHdrs(std::vector<STG_MSG_HDR> * hdrsList, const std::string & login) const
1996 {
1997 MYSQL_RES *res;
1998 MYSQL_ROW row;
1999 MYSQL * sock;
2000 sprintf(qbuf,"SELECT * FROM messages WHERE login='%s'", login.c_str());
2001     
2002 if(MysqlGetQuery(qbuf,sock))
2003 {
2004     errorStr = "Couldn't GetMessageHdrs:\n";
2005     errorStr += mysql_error(sock);
2006     mysql_close(sock);
2007     return -1;
2008 }
2009
2010 if (!(res=mysql_store_result(sock)))
2011 {
2012     errorStr = "Couldn't GetMessageHdrs:\n";
2013     errorStr += mysql_error(sock);
2014     mysql_close(sock);
2015     return -1;
2016 }
2017
2018 unsigned int i;
2019 my_ulonglong num_rows = mysql_num_rows(res);
2020 uint64_t id = 0;
2021
2022 for (i = 0; i < num_rows; i++)
2023 {
2024     row = mysql_fetch_row(res);
2025     if (str2x(row[1], id))
2026         continue;
2027     
2028     STG_MSG_HDR hdr;
2029     if (row[2]) 
2030         if(str2x(row[2], hdr.type))
2031             continue;
2032
2033     if (row[3])
2034         if(str2x(row[3], hdr.lastSendTime))
2035             continue;
2036
2037     if (row[4])
2038         if(str2x(row[4], hdr.creationTime))
2039             continue;
2040
2041     if (row[5])
2042         if(str2x(row[5], hdr.showTime))
2043             continue;
2044
2045     if (row[6])
2046         if(str2x(row[6], hdr.repeat))
2047             continue;
2048
2049     if (row[7])
2050         if(str2x(row[7], hdr.repeatPeriod))
2051             continue;
2052
2053     hdr.id = id;
2054     hdrsList->push_back(hdr);
2055 }
2056
2057 mysql_free_result(res);
2058 mysql_close(sock);
2059 return 0;
2060 }
2061 //-----------------------------------------------------------------------------
2062
2063 int MYSQL_STORE::MysqlSetQuery(const char * Query) const {
2064
2065     MYSQL * sock;
2066     int ret=MysqlGetQuery(Query,sock);
2067     mysql_close(sock);
2068     return ret;
2069 }
2070 //-----------------------------------------------------------------------------
2071 int  MYSQL_STORE::MysqlGetQuery(const char * Query,MYSQL * & sock) const {
2072     if (!(sock=MysqlConnect())) {
2073         return -1;
2074     }
2075     return   MysqlQuery(Query,sock);
2076 }
2077 //-----------------------------------------------------------------------------
2078 MYSQL *  MYSQL_STORE::MysqlConnect() const {
2079     MYSQL * sock;
2080     if ( !(sock=mysql_init(NULL)) ){
2081         errorStr= "mysql init susck\n";
2082         return NULL;
2083     }
2084     if (!(sock = mysql_real_connect(sock,storeSettings.GetDBHost().c_str(),
2085             storeSettings.GetDBUser().c_str(),storeSettings.GetDBPassword().c_str(),
2086             0,0,NULL,0)))
2087         {
2088             errorStr = "Couldn't connect to mysql engine! With error:\n";
2089             errorStr += mysql_error(sock);
2090             return NULL;
2091         }
2092     else{
2093          if(mysql_select_db(sock, storeSettings.GetDBName().c_str())){
2094              errorStr = "Database lost !\n";
2095              return NULL;
2096          }
2097     }
2098     return sock;
2099 }
2100 //-----------------------------------------------------------------------------