]> git.stg.codes - stg.git/blob - projects/stargazer/plugins/store/mysql/mysql_store.cpp
Added config serializer.
[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       logger(GetPluginLogger(GetStgLogger(), "store_mysql"))
167 {
168 }
169 //-----------------------------------------------------------------------------
170 int    MYSQL_STORE::MysqlQuery(const char* sQuery,MYSQL * sock) const
171 {
172     int ret;
173
174     if( (ret = mysql_query(sock,sQuery)) )
175     {
176         for(int i=0; i<RepitTimes; i++)
177         {
178             if( (ret = mysql_query(sock,sQuery)) )
179                 ;//need to send error result
180             else
181                 return 0;
182         }
183     }
184     
185     return ret;
186 }
187 //-----------------------------------------------------------------------------
188
189 //-----------------------------------------------------------------------------
190 int MYSQL_STORE::ParseSettings()
191 {
192 int ret = storeSettings.ParseSettings(settings);
193 MYSQL mysql;
194 MYSQL * sock;
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     
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='',Userdata0='',"\
504         "Userdata1='',";
505     
506     for (int i = 0; i < DIR_NUM; i++)
507         {
508         strprintf(&param, " D%d=0,", i);
509         res += param;
510     
511         strprintf(&param, " U%d=0,", i);
512         res += param;
513         }
514     
515     res += "Cash=10.0,FreeMb=0.0,LastActivityTime=0,LastCashAdd=0,"\
516         "LastCashAddTime=0, PassiveTime=0";
517         
518     if(MysqlQuery(res.c_str(),sock))
519     {
520         errorStr = "Couldn't create default user. With error:\n";
521         errorStr += mysql_error(sock);
522         mysql_close(sock);
523         return -1;
524     }
525 }
526 /*
527 //logs-----------------------------------------------------------------------
528 if(!IsTablePresent("logs"))
529 {
530     sprintf(qbuf,"CREATE TABLE logs (unid INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, login VARCHAR(40),text TEXT)");
531     
532     if(MysqlQuery(qbuf))
533     {
534         errorStr = "Couldn't create admin table list With error:\n";
535         errorStr += mysql_error(sock);
536         return -1;
537     }
538 }
539 */
540 //messages---------------------------------------------------------------------
541 if(!IsTablePresent("messages",sock))
542 {
543     sprintf(qbuf,"CREATE TABLE messages (login VARCHAR(40) DEFAULT '', id BIGINT, "\
544             "type INT, lastSendTime INT, creationTime INT, showTime INT,"\
545             "stgRepeat INT, repeatPeriod INT, text TEXT)");
546     
547     if(MysqlQuery(qbuf,sock))
548     {
549         errorStr = "Couldn't create messages table. With error:\n";
550         errorStr += mysql_error(sock);
551         mysql_close(sock);
552         return -1;
553     }
554 }
555
556 //month_stat-------------------------------------------------------------------
557 if(!IsTablePresent("stat",sock))
558 {
559     res = "CREATE TABLE stat (login VARCHAR(50), month TINYINT, year SMALLINT,";
560     
561     for (int i = 0; i < DIR_NUM; i++)
562         {
563         strprintf(&param, " U%d BIGINT,", i); 
564         res += param;
565             
566         strprintf(&param, " D%d BIGINT,", i); 
567         res += param;
568         }
569         
570     res += " cash DOUBLE, INDEX (login))";
571     
572     if(MysqlQuery(res.c_str(),sock))
573     {
574         errorStr = "Couldn't create stat table. With error:\n";
575         errorStr += mysql_error(sock);
576         mysql_close(sock);
577         return -1;
578     }
579 }
580
581 return 0;
582 }
583 //-----------------------------------------------------------------------------
584 int MYSQL_STORE::MakeUpdates(MYSQL * sock)
585 {
586 if (schemaVersion  < 1)
587     {
588     if (MysqlQuery("ALTER TABLE tariffs ADD period VARCHAR(32) NOT NULL DEFAULT 'month'", sock))
589         {
590         errorStr = "Couldn't update tariffs table to version 1. With error:\n";
591         errorStr += mysql_error(sock);
592         mysql_close(sock);
593         return -1;
594         }
595     if (MysqlQuery("UPDATE info SET version = 1", sock))
596         {
597         errorStr = "Couldn't update DB schema version to 1. With error:\n";
598         errorStr += mysql_error(sock);
599         mysql_close(sock);
600         return -1;
601         }
602     schemaVersion = 1;
603     logger("MYSQL_STORE: Updated DB schema to version %d", schemaVersion);
604     }
605 return 0;
606 }
607 //-----------------------------------------------------------------------------
608
609 int MYSQL_STORE::GetAllParams(std::vector<std::string> * ParamList, 
610                             const std::string & table, const std::string & name) const
611 {
612 MYSQL_RES *res;
613 MYSQL_ROW row;
614 MYSQL * sock=NULL;
615 my_ulonglong num, i;
616     
617 ParamList->clear();
618     
619 sprintf(qbuf,"SELECT %s FROM %s", name.c_str(), table.c_str());
620     
621 if(MysqlGetQuery(qbuf,sock))
622 {
623     errorStr = "Couldn't GetAllParams Query for: ";
624     errorStr += name + " - " + table + "\n";
625     errorStr += mysql_error(sock);
626     mysql_close(sock);
627     return -1;
628 }
629
630 if (!(res=mysql_store_result(sock)))
631 {
632     errorStr = "Couldn't GetAllParams Results for: ";
633     errorStr += name + " - " + table + "\n";
634     errorStr += mysql_error(sock);
635     return -1;
636 }
637
638 num = mysql_num_rows(res);
639
640 for(i = 0; i < num; i++)
641 {
642     row = mysql_fetch_row(res);    
643     ParamList->push_back(row[0]);
644 }
645
646 mysql_free_result(res);
647 mysql_close(sock);
648
649 return 0;
650 }
651
652 //-----------------------------------------------------------------------------
653 int MYSQL_STORE::GetUsersList(std::vector<std::string> * usersList) const
654 {
655 if(GetAllParams(usersList, "users", "login"))
656     return -1;
657
658 return 0;
659 }
660 //-----------------------------------------------------------------------------
661 int MYSQL_STORE::GetAdminsList(std::vector<std::string> * adminsList) const
662 {
663 if(GetAllParams(adminsList, "admins", "login"))
664     return -1;
665
666 return 0;
667 }
668 //-----------------------------------------------------------------------------
669 int MYSQL_STORE::GetTariffsList(std::vector<std::string> * tariffsList) const
670 {
671 if(GetAllParams(tariffsList, "tariffs", "name"))
672     return -1;
673
674 return 0;
675 }
676 //-----------------------------------------------------------------------------
677 int MYSQL_STORE::AddUser(const std::string & login) const
678 {
679 sprintf(qbuf,"INSERT INTO users SET login='%s'", login.c_str());
680     
681 if(MysqlSetQuery(qbuf))
682 {
683     errorStr = "Couldn't add user:\n";
684     //errorStr += mysql_error(sock);
685     return -1;
686 }
687
688 return 0;
689 }
690 //-----------------------------------------------------------------------------
691 int MYSQL_STORE::DelUser(const std::string & login) const
692 {
693 sprintf(qbuf,"DELETE FROM users WHERE login='%s' LIMIT 1", login.c_str());
694     
695 if(MysqlSetQuery(qbuf))
696 {
697     errorStr = "Couldn't delete user:\n";
698     //errorStr += mysql_error(sock);
699     return -1;
700 }
701
702 return 0;
703 }
704 //-----------------------------------------------------------------------------
705 int MYSQL_STORE::RestoreUserConf(USER_CONF * conf, const std::string & login) const
706 {
707 MYSQL_RES *res;
708 MYSQL_ROW row;
709 MYSQL * sock;
710 std::string query;
711
712 query = "SELECT login, Password, Passive, Down, DisabledDetailStat, \
713          AlwaysOnline, Tariff, Address, Phone, Email, Note, \
714          RealName, StgGroup, Credit, TariffChange, ";
715
716 for (int i = 0; i < USERDATA_NUM; i++)
717 {
718     sprintf(qbuf, "Userdata%d, ", i);
719     query += qbuf;
720 }
721
722 query += "CreditExpire, IP FROM users WHERE login='";
723 query += login + "' LIMIT 1";
724
725 //sprintf(qbuf,"SELECT * FROM users WHERE login='%s' LIMIT 1", login.c_str());
726     
727 if(MysqlGetQuery(query.c_str(),sock))
728 {
729     errorStr = "Couldn't restore Tariff(on query):\n";
730     errorStr += mysql_error(sock);
731     mysql_close(sock);
732     return -1;
733 }
734
735 if (!(res=mysql_store_result(sock)))
736 {
737     errorStr = "Couldn't restore Tariff(on getting result):\n";
738     errorStr += mysql_error(sock);
739     mysql_close(sock);
740     return -1;
741 }
742
743 if (mysql_num_rows(res) != 1)
744 {
745     errorStr = "User not found";
746     mysql_close(sock);
747     return -1;
748 }
749
750 row = mysql_fetch_row(res);
751
752 std::string param;
753
754 conf->password = row[1];
755
756 if (conf->password.empty())
757     {
758     mysql_free_result(res);
759     errorStr = "User \'" + login + "\' password is blank.";
760     mysql_close(sock);
761     return -1;
762     }
763
764 if (GetInt(row[2],&conf->passive) != 0)
765     {
766     mysql_free_result(res);
767     errorStr = "User \'" + login + "\' data not read. Parameter Passive.";
768     mysql_close(sock);
769     return -1;
770     }
771
772 if (GetInt(row[3], &conf->disabled) != 0)
773     {
774     mysql_free_result(res);
775     errorStr = "User \'" + login + "\' data not read. Parameter Down.";
776     mysql_close(sock);
777     return -1;
778     }
779
780 if (GetInt(row[4], &conf->disabledDetailStat) != 0)
781     {
782     mysql_free_result(res);
783     errorStr = "User \'" + login + "\' data not read. Parameter DisabledDetailStat.";
784     mysql_close(sock);
785     return -1;
786     }
787
788 if (GetInt(row[5], &conf->alwaysOnline) != 0)
789     {
790     mysql_free_result(res);
791     errorStr = "User \'" + login + "\' data not read. Parameter AlwaysOnline.";
792     mysql_close(sock);
793     return -1;
794     }
795
796 conf->tariffName = row[6];
797
798 if (conf->tariffName.empty()) 
799     {
800     mysql_free_result(res);
801     errorStr = "User \'" + login + "\' tariff is blank.";
802     mysql_close(sock);
803     return -1;
804     }
805
806 conf->address = row[7];
807 conf->phone = row[8];
808 conf->email = row[9];
809 conf->note = row[10];
810 conf->realName = row[11];
811 conf->group = row[12];
812
813 if (GetDouble(row[13], &conf->credit, 0) != 0)
814     {
815     mysql_free_result(res);
816     errorStr = "User \'" + login + "\' data not read. Parameter Credit.";
817     mysql_close(sock);
818     return -1;
819     }
820
821 conf->nextTariff = row[14];
822
823 for (int i = 0; i < USERDATA_NUM; i++)
824     {
825     conf->userdata[i] = row[15+i];
826     }
827
828 GetTime(row[15+USERDATA_NUM], &conf->creditExpire, 0);
829     
830 std::string ipStr = row[16+USERDATA_NUM];
831 USER_IPS i;
832 try
833     {
834     i = StrToIPS(ipStr);
835     }
836 catch (const std::string & s)
837     {
838     mysql_free_result(res);
839     errorStr = "User \'" + login + "\' data not read. Parameter IP address. " + s;
840     mysql_close(sock);
841     return -1;
842     }
843 conf->ips = i;
844
845 mysql_free_result(res);
846 mysql_close(sock);
847
848 return 0;
849 }
850 //-----------------------------------------------------------------------------
851 int MYSQL_STORE::RestoreUserStat(USER_STAT * stat, const std::string & login) const
852 {
853 MYSQL_RES *res;
854 MYSQL_ROW row;
855 MYSQL * sock;
856
857 std::string query;
858
859 query = "SELECT ";
860
861 for (int i = 0; i < DIR_NUM; i++)
862 {
863     sprintf(qbuf, "D%d, U%d, ", i, i);
864     query += qbuf;
865 }
866
867 query += "Cash, FreeMb, LastCashAdd, LastCashAddTime, PassiveTime, LastActivityTime \
868           FROM users WHERE login = '";
869 query += login + "'";
870
871 //sprintf(qbuf,"SELECT * FROM users WHERE login='%s' LIMIT 1", login.c_str());
872     
873 if(MysqlGetQuery(query.c_str() ,sock))
874 {
875     errorStr = "Couldn't restore UserStat(on query):\n";
876     errorStr += mysql_error(sock);
877     mysql_close(sock);
878     return -1;
879 }
880
881 if (!(res=mysql_store_result(sock)))
882 {
883     errorStr = "Couldn't restore UserStat(on getting result):\n";
884     errorStr += mysql_error(sock);
885     mysql_close(sock);
886     return -1;
887 }
888
889 row = mysql_fetch_row(res);
890
891 unsigned int startPos=0;
892
893 char s[22];
894
895 for (int i = 0; i < DIR_NUM; i++)
896     {
897     uint64_t traff;
898     sprintf(s, "D%d", i);
899     if (GetULongLongInt(row[startPos+i*2], &traff, 0) != 0)
900         {
901         mysql_free_result(res);
902         errorStr = "User \'" + login + "\' stat not read. Parameter " + std::string(s);
903         mysql_close(sock);
904         return -1;
905         }
906     stat->monthDown[i] = traff;
907
908     sprintf(s, "U%d", i);
909     if (GetULongLongInt(row[startPos+i*2+1], &traff, 0) != 0)
910         {
911         mysql_free_result(res);
912         errorStr =   "User \'" + login + "\' stat not read. Parameter " + std::string(s);
913         mysql_close(sock);
914         return -1;
915         }
916     stat->monthUp[i] = traff;
917     }//for
918
919 startPos += (2*DIR_NUM);
920
921 if (GetDouble(row[startPos], &stat->cash, 0) != 0)
922     {
923     mysql_free_result(res);
924     errorStr =   "User \'" + login + "\' stat not read. Parameter Cash";
925     mysql_close(sock);
926     return -1;
927     }
928
929 if (GetDouble(row[startPos+1],&stat->freeMb, 0) != 0)
930     {
931     mysql_free_result(res);
932     errorStr =   "User \'" + login + "\' stat not read. Parameter FreeMb";
933     mysql_close(sock);
934     return -1;
935     }
936
937 if (GetDouble(row[startPos+2], &stat->lastCashAdd, 0) != 0)
938     {
939     mysql_free_result(res);
940     errorStr =   "User \'" + login + "\' stat not read. Parameter LastCashAdd";
941     mysql_close(sock);
942     return -1;
943     }
944
945 if (GetTime(row[startPos+3], &stat->lastCashAddTime, 0) != 0)
946     {
947     mysql_free_result(res);
948     errorStr =   "User \'" + login + "\' stat not read. Parameter LastCashAddTime";
949     mysql_close(sock);
950     return -1;
951     }
952
953 if (GetTime(row[startPos+4], &stat->passiveTime, 0) != 0)
954     {
955     mysql_free_result(res);
956     errorStr =   "User \'" + login + "\' stat not read. Parameter PassiveTime";
957     mysql_close(sock);
958     return -1;
959     }
960
961 if (GetTime(row[startPos+5], &stat->lastActivityTime, 0) != 0)
962     {
963     mysql_free_result(res);
964     errorStr =   "User \'" + login + "\' stat not read. Parameter LastActivityTime";
965     mysql_close(sock);
966     return -1;
967     }
968
969 mysql_free_result(res);
970 mysql_close(sock);
971 return 0;
972 }
973 //-----------------------------------------------------------------------------
974 int MYSQL_STORE::SaveUserConf(const USER_CONF & conf, const std::string & login) const
975 {
976 std::string param;
977 std::string res;
978
979 strprintf(&res,"UPDATE users SET Password='%s', Passive=%d, Down=%d, DisabledDetailStat = %d, "\
980     "AlwaysOnline=%d, Tariff='%s', Address='%s', Phone='%s', Email='%s', "\
981     "Note='%s', RealName='%s', StgGroup='%s', Credit=%f, TariffChange='%s', ", 
982     conf.password.c_str(),
983     conf.passive,
984     conf.disabled,
985     conf.disabledDetailStat,
986     conf.alwaysOnline,
987     conf.tariffName.c_str(),
988     (ReplaceStr(conf.address,badSyms,repSym)).c_str(),
989     (ReplaceStr(conf.phone,badSyms,repSym)).c_str(),
990     (ReplaceStr(conf.email,badSyms,repSym)).c_str(),
991     (ReplaceStr(conf.note,badSyms,repSym)).c_str(),
992     (ReplaceStr(conf.realName,badSyms,repSym)).c_str(),
993     (ReplaceStr(conf.group,badSyms,repSym)).c_str(),
994     conf.credit,
995     conf.nextTariff.c_str()
996     );
997
998 for (int i = 0; i < USERDATA_NUM; i++)
999     {
1000     strprintf(&param, " Userdata%d='%s',", i, 
1001         (ReplaceStr(conf.userdata[i],badSyms,repSym)).c_str());
1002     res += param;
1003     }
1004     
1005 strprintf(&param, " CreditExpire=%d,", conf.creditExpire);
1006 res += param;
1007
1008 std::ostringstream ipStr;
1009 ipStr << conf.ips;
1010
1011 strprintf(&param, " IP='%s'", ipStr.str().c_str());
1012 res += param;
1013
1014 strprintf(&param, " WHERE login='%s' LIMIT 1", login.c_str());
1015 res += param;
1016
1017 if(MysqlSetQuery(res.c_str()))
1018 {
1019     errorStr = "Couldn't save user conf:\n";
1020     //errorStr += mysql_error(sock);
1021     return -1;
1022 }
1023
1024 return 0;
1025 }
1026 //-----------------------------------------------------------------------------
1027 int MYSQL_STORE::SaveUserStat(const USER_STAT & stat, const std::string & login) const
1028 {
1029 std::string param;
1030 std::string res;
1031
1032 res = "UPDATE users SET";
1033
1034 for (int i = 0; i < DIR_NUM; i++)
1035     {
1036     strprintf(&param, " D%d=%lld,", i, stat.monthDown[i]);
1037     res += param;
1038
1039     strprintf(&param, " U%d=%lld,", i, stat.monthUp[i]);
1040     res += param;
1041     }
1042
1043 strprintf(&param, " Cash=%f, FreeMb=%f, LastCashAdd=%f, LastCashAddTime=%d,"\
1044     " PassiveTime=%d, LastActivityTime=%d", 
1045     stat.cash,
1046     stat.freeMb,
1047     stat.lastCashAdd,
1048     stat.lastCashAddTime,
1049     stat.passiveTime,
1050     stat.lastActivityTime
1051     );
1052 res += param;
1053
1054 strprintf(&param, " WHERE login='%s' LIMIT 1", login.c_str());
1055 res += param;
1056
1057 if(MysqlSetQuery(res.c_str()))
1058 {
1059     errorStr = "Couldn't save user stat:\n";
1060 //    errorStr += mysql_error(sock);
1061     return -1;
1062 }
1063
1064 return 0;
1065 }
1066 //-----------------------------------------------------------------------------
1067 int MYSQL_STORE::WriteLogString(const std::string & str, const std::string & login) const
1068 {
1069 std::string res, tempStr;
1070 time_t t;
1071 tm * lt;
1072
1073 t = time(NULL);
1074 lt = localtime(&t);
1075
1076 MYSQL_RES* result;
1077 MYSQL * sock;
1078 strprintf(&tempStr, "logs_%02d_%4d", lt->tm_mon+1, lt->tm_year+1900);
1079 if (!(sock=MysqlConnect())){
1080     errorStr = "Couldn't connect to Server";
1081     return -1;
1082 }
1083 if (!(result=mysql_list_tables(sock,tempStr.c_str() )))
1084 {
1085     errorStr = "Couldn't get table " + tempStr + ":\n";
1086     errorStr += mysql_error(sock);
1087     mysql_close(sock);
1088     return -1;
1089 }
1090
1091 my_ulonglong num_rows =  mysql_num_rows(result);
1092
1093 mysql_free_result(result);
1094
1095 if (num_rows < 1)
1096 {
1097     sprintf(qbuf,"CREATE TABLE logs_%02d_%4d (unid INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, login VARCHAR(40),text TEXT)",
1098     lt->tm_mon+1, lt->tm_year+1900);
1099     
1100     if(MysqlQuery(qbuf,sock))
1101     {
1102         errorStr = "Couldn't create WriteDetailedStat table:\n";
1103         errorStr += mysql_error(sock);
1104         mysql_close(sock);
1105         return -1;
1106     }
1107 }
1108
1109 strprintf(&res, "%s -- %s",LogDate(t), str.c_str());
1110
1111 std::string send;
1112
1113 strprintf(&send,"INSERT INTO logs_%02d_%4d SET login='%s', text='%s'",
1114         lt->tm_mon+1, lt->tm_year+1900,
1115     login.c_str(), (ReplaceStr(res,badSyms,repSym)).c_str());
1116
1117 if(MysqlQuery(send.c_str(),sock))
1118 {
1119     errorStr = "Couldn't write log string:\n";
1120     errorStr += mysql_error(sock);
1121     mysql_close(sock);
1122     return -1;
1123 }
1124 mysql_close(sock);
1125 return 0;
1126
1127 }
1128 //-----------------------------------------------------------------------------
1129 int MYSQL_STORE::WriteUserChgLog(const std::string & login,
1130                                  const std::string & admLogin,
1131                                  uint32_t       admIP,
1132                                  const std::string & paramName,
1133                                  const std::string & oldValue,
1134                                  const std::string & newValue,
1135                                  const std::string & message) const
1136 {
1137 std::string userLogMsg = "Admin \'" + admLogin + "\', " + inet_ntostring(admIP) + ": \'"
1138     + paramName + "\' parameter changed from \'" + oldValue +
1139     "\' to \'" + newValue + "\'. " + message;
1140
1141 return WriteLogString(userLogMsg, login);
1142 }
1143 //-----------------------------------------------------------------------------
1144 int MYSQL_STORE::WriteUserConnect(const std::string & login, uint32_t ip) const
1145 {
1146 std::string logStr = "Connect, " + inet_ntostring(ip);
1147 return WriteLogString(logStr, login);
1148 }
1149 //-----------------------------------------------------------------------------
1150 int MYSQL_STORE::WriteUserDisconnect(const std::string & login,
1151                                      const DIR_TRAFF & up,
1152                                      const DIR_TRAFF & down,
1153                                      const DIR_TRAFF & sessionUp,
1154                                      const DIR_TRAFF & sessionDown,
1155                                      double cash,
1156                                      double /*freeMb*/,
1157                                      const std::string & /*reason*/) const
1158 {
1159 std::string logStr = "Disconnect, ";
1160 std::ostringstream sssu;
1161 std::ostringstream sssd;
1162 std::ostringstream ssmu;
1163 std::ostringstream ssmd;
1164 std::ostringstream sscash;
1165
1166 ssmu << up;
1167 ssmd << down;
1168
1169 sssu << sessionUp;
1170 sssd << sessionDown;
1171
1172 sscash << cash;
1173
1174 logStr += " session upload: \'";
1175 logStr += sssu.str();
1176 logStr += "\' session download: \'";
1177 logStr += sssd.str();
1178 logStr += "\' month upload: \'";
1179 logStr += ssmu.str();
1180 logStr += "\' month download: \'";
1181 logStr += ssmd.str();
1182 logStr += "\' cash: \'";
1183 logStr += sscash.str();
1184 logStr += "\'";
1185
1186 return WriteLogString(logStr, login);
1187 }
1188 //-----------------------------------------------------------------------------
1189 int MYSQL_STORE::SaveMonthStat(const USER_STAT & stat, int month, int year, 
1190                                 const std::string & login) const
1191 {
1192 std::string param, res;
1193
1194 strprintf(&res, "INSERT INTO stat SET login='%s', month=%d, year=%d,", 
1195     login.c_str(), month+1, year+1900);
1196     
1197 for (int i = 0; i < DIR_NUM; i++)
1198     {
1199     strprintf(&param, " U%d=%lld,", i, stat.monthUp[i]); 
1200     res += param;
1201
1202     strprintf(&param, " D%d=%lld,", i, stat.monthDown[i]);        
1203     res += param;
1204     }
1205     
1206 strprintf(&param, " cash=%f", stat.cash);        
1207 res += param;
1208
1209 if(MysqlSetQuery(res.c_str()))
1210 {
1211     errorStr = "Couldn't SaveMonthStat:\n";
1212     //errorStr += mysql_error(sock);
1213     return -1;
1214 }
1215
1216 return 0;
1217 }
1218 //-----------------------------------------------------------------------------*/
1219 int MYSQL_STORE::AddAdmin(const std::string & login) const
1220 {
1221 sprintf(qbuf,"INSERT INTO admins SET login='%s'", login.c_str());
1222     
1223 if(MysqlSetQuery(qbuf))
1224 {
1225     errorStr = "Couldn't add admin:\n";
1226     //errorStr += mysql_error(sock);
1227     return -1;
1228 }
1229
1230 return 0;
1231 }
1232 //-----------------------------------------------------------------------------*/
1233 int MYSQL_STORE::DelAdmin(const std::string & login) const
1234 {
1235 sprintf(qbuf,"DELETE FROM admins where login='%s' LIMIT 1", login.c_str());
1236     
1237 if(MysqlSetQuery(qbuf))
1238 {
1239     errorStr = "Couldn't delete admin:\n";
1240     //errorStr += mysql_error(sock);
1241     return -1;
1242 }
1243
1244 return 0;
1245 }
1246 //-----------------------------------------------------------------------------*/
1247 int MYSQL_STORE::SaveAdmin(const ADMIN_CONF & ac) const
1248 {
1249 char passwordE[2 * ADM_PASSWD_LEN + 2];
1250 char pass[ADM_PASSWD_LEN + 1];
1251 char adminPass[ADM_PASSWD_LEN + 1];
1252
1253 memset(pass, 0, sizeof(pass));
1254 memset(adminPass, 0, sizeof(adminPass));
1255
1256 BLOWFISH_CTX ctx;
1257 EnDecodeInit(adm_enc_passwd, strlen(adm_enc_passwd), &ctx);
1258
1259 strncpy(adminPass, ac.password.c_str(), ADM_PASSWD_LEN);
1260 adminPass[ADM_PASSWD_LEN - 1] = 0;
1261
1262 for (int i = 0; i < ADM_PASSWD_LEN/8; i++)
1263     {
1264     EncodeString(pass + 8*i, adminPass + 8*i, &ctx);
1265     }
1266
1267 pass[ADM_PASSWD_LEN - 1] = 0;
1268 Encode12(passwordE, pass, ADM_PASSWD_LEN);
1269
1270 sprintf(qbuf,"UPDATE admins SET password='%s', ChgConf=%d, ChgPassword=%d, "\
1271     "ChgStat=%d, ChgCash=%d, UsrAddDel=%d, ChgTariff=%d, ChgAdmin=%d "\
1272     "WHERE login='%s' LIMIT 1", 
1273     passwordE,
1274     ac.priv.userConf,
1275     ac.priv.userPasswd,
1276     ac.priv.userStat,
1277     ac.priv.userCash,
1278     ac.priv.userAddDel,
1279     ac.priv.tariffChg,
1280     ac.priv.adminChg,
1281     ac.login.c_str()
1282     );
1283
1284 if(MysqlSetQuery(qbuf))
1285 {
1286     errorStr = "Couldn't save admin:\n";
1287     //errorStr += mysql_error(sock);
1288     return -1;
1289 }
1290
1291 return 0;
1292 }
1293 //-----------------------------------------------------------------------------
1294 int MYSQL_STORE::RestoreAdmin(ADMIN_CONF * ac, const std::string & login) const
1295 {
1296 char pass[ADM_PASSWD_LEN + 1];
1297 char password[ADM_PASSWD_LEN + 1];
1298 char passwordE[2*ADM_PASSWD_LEN + 2];
1299 BLOWFISH_CTX ctx;
1300
1301 memset(pass, 0, sizeof(pass));
1302 memset(password, 0, sizeof(password));
1303 memset(passwordE, 0, sizeof(passwordE));
1304
1305 std::string p;
1306 MYSQL_RES *res;
1307 MYSQL_ROW row;
1308 MYSQL * sock;
1309 sprintf(qbuf,"SELECT * FROM admins WHERE login='%s' LIMIT 1", login.c_str());
1310     
1311 if(MysqlGetQuery(qbuf,sock))
1312 {
1313     errorStr = "Couldn't restore admin:\n";
1314     errorStr += mysql_error(sock);
1315     mysql_close(sock);
1316     return -1;
1317 }
1318
1319 if (!(res=mysql_store_result(sock)))
1320 {
1321     errorStr = "Couldn't restore admin:\n";
1322     errorStr += mysql_error(sock);
1323     mysql_close(sock);
1324     return -1;
1325 }
1326
1327 if ( mysql_num_rows(res) == 0)
1328 {
1329     mysql_free_result(res);
1330     errorStr = "Couldn't restore admin as couldn't found him in table.\n";
1331     mysql_close(sock);
1332     return -1;
1333 }
1334   
1335 row = mysql_fetch_row(res);
1336
1337 p = row[1];
1338
1339 if(p.length() == 0)
1340 {
1341     mysql_free_result(res);
1342     errorStr = "Error in parameter password";
1343     mysql_close(sock);
1344     return -1;
1345 }
1346
1347 memset(passwordE, 0, sizeof(passwordE));
1348 strncpy(passwordE, p.c_str(), 2*ADM_PASSWD_LEN);
1349
1350 memset(pass, 0, sizeof(pass));
1351
1352 if (passwordE[0] != 0)
1353     {
1354     Decode21(pass, passwordE);
1355     EnDecodeInit(adm_enc_passwd, strlen(adm_enc_passwd), &ctx);
1356
1357     for (int i = 0; i < ADM_PASSWD_LEN/8; i++)
1358         {
1359         DecodeString(password + 8*i, pass + 8*i, &ctx);
1360         }
1361     }
1362 else
1363     {
1364     password[0] = 0;
1365     }
1366
1367 ac->password = password;
1368
1369 uint16_t a;
1370
1371 if (GetInt(row[2], &a) == 0) 
1372     ac->priv.userConf = a;
1373 else
1374     {
1375     mysql_free_result(res);
1376     errorStr = "Error in parameter ChgConf";
1377     mysql_close(sock);
1378     return -1;
1379     }
1380
1381 if (GetInt(row[3], &a) == 0) 
1382     ac->priv.userPasswd = a;
1383 else
1384     {
1385     mysql_free_result(res);
1386     errorStr = "Error in parameter ChgPassword";
1387     mysql_close(sock);
1388     return -1;
1389     }
1390
1391 if (GetInt(row[4], &a) == 0) 
1392     ac->priv.userStat = a;
1393 else
1394     {
1395     mysql_free_result(res);
1396     errorStr = "Error in parameter ChgStat";
1397     mysql_close(sock);
1398     return -1;
1399     }
1400
1401 if (GetInt(row[5], &a) == 0) 
1402     ac->priv.userCash = a;
1403 else
1404     {
1405     mysql_free_result(res);
1406     errorStr = "Error in parameter ChgCash";
1407     mysql_close(sock);
1408     return -1;
1409     }
1410
1411 if (GetInt(row[6], &a) == 0) 
1412     ac->priv.userAddDel = a;
1413 else
1414     {
1415     mysql_free_result(res);
1416     errorStr = "Error in parameter UsrAddDel";
1417     mysql_close(sock);
1418     return -1;
1419     }
1420
1421 if (GetInt(row[7], &a) == 0) 
1422     ac->priv.tariffChg = a;
1423 else
1424     {
1425     mysql_free_result(res);
1426     errorStr = "Error in parameter ChgTariff";
1427     mysql_close(sock);
1428     return -1;
1429     }
1430
1431 if (GetInt(row[8], &a) == 0) 
1432     ac->priv.adminChg = a;
1433 else
1434     {
1435     mysql_free_result(res);
1436     errorStr = "Error in parameter ChgAdmin";
1437     mysql_close(sock);
1438     return -1;
1439     }
1440
1441 mysql_free_result(res);
1442 mysql_close(sock);
1443 return 0;
1444 }
1445 //-----------------------------------------------------------------------------
1446 int MYSQL_STORE::AddTariff(const std::string & name) const
1447 {
1448 sprintf(qbuf,"INSERT INTO tariffs SET name='%s'", name.c_str());
1449     
1450 if(MysqlSetQuery(qbuf))
1451 {
1452     errorStr = "Couldn't add tariff:\n";
1453 //    errorStr += mysql_error(sock);
1454     return -1;
1455 }
1456
1457 return 0;
1458 }
1459 //-----------------------------------------------------------------------------
1460 int MYSQL_STORE::DelTariff(const std::string & name) const
1461 {
1462 sprintf(qbuf,"DELETE FROM tariffs WHERE name='%s' LIMIT 1", name.c_str());
1463     
1464 if(MysqlSetQuery(qbuf))
1465 {
1466     errorStr = "Couldn't delete tariff: ";
1467 //    errorStr += mysql_error(sock);
1468     return -1;
1469 }
1470
1471 return 0;
1472 }
1473 //-----------------------------------------------------------------------------
1474 int MYSQL_STORE::RestoreTariff(TARIFF_DATA * td, const std::string & tariffName) const
1475 {
1476 MYSQL_RES *res;
1477 MYSQL_ROW row;
1478 MYSQL * sock;
1479 sprintf(qbuf,"SELECT * FROM tariffs WHERE name='%s' LIMIT 1", tariffName.c_str());
1480     
1481 if(MysqlGetQuery(qbuf,sock))
1482 {
1483     errorStr = "Couldn't restore Tariff:\n";
1484     errorStr += mysql_error(sock);
1485     mysql_close(sock);
1486     return -1;
1487 }
1488
1489 if (!(res=mysql_store_result(sock)))
1490 {
1491     errorStr = "Couldn't restore Tariff:\n";
1492     errorStr += mysql_error(sock);
1493     mysql_close(sock);
1494     return -1;
1495 }
1496
1497 std::string str;
1498 td->tariffConf.name = tariffName;
1499
1500 row = mysql_fetch_row(res);
1501
1502 std::string param;
1503 for (int i = 0; i<DIR_NUM; i++)
1504     {
1505     strprintf(&param, "Time%d", i);
1506     str = row[6+i*8];
1507     if (str.length() == 0)
1508         {
1509         mysql_free_result(res);
1510         errorStr = "Cannot read tariff " + tariffName + ". Parameter " + param;
1511         mysql_close(sock);
1512         return -1;
1513         }
1514
1515     ParseTariffTimeStr(str.c_str(), 
1516                        td->dirPrice[i].hDay, 
1517                        td->dirPrice[i].mDay, 
1518                        td->dirPrice[i].hNight, 
1519                        td->dirPrice[i].mNight);
1520
1521     strprintf(&param, "PriceDayA%d", i);
1522     if (GetDouble(row[1+i*8], &td->dirPrice[i].priceDayA, 0.0) < 0)
1523         {
1524         mysql_free_result(res);
1525         errorStr = "Cannot read tariff " + tariffName + ". Parameter " + param;
1526         mysql_close(sock);
1527         return -1;
1528         }
1529     td->dirPrice[i].priceDayA /= (1024*1024);
1530
1531     strprintf(&param, "PriceDayB%d", i);
1532     if (GetDouble(row[2+i*8], &td->dirPrice[i].priceDayB, 0.0) < 0)
1533         {
1534         mysql_free_result(res);
1535         errorStr = "Cannot read tariff " + tariffName + ". Parameter " + param;
1536         mysql_close(sock);
1537         return -1;
1538         }
1539     td->dirPrice[i].priceDayB /= (1024*1024);
1540
1541     strprintf(&param, "PriceNightA%d", i);
1542     if (GetDouble(row[3+i*8], &td->dirPrice[i].priceNightA, 0.0) < 0)
1543         {
1544         mysql_free_result(res);
1545         errorStr = "Cannot read tariff " + tariffName + ". Parameter " + param;
1546         mysql_close(sock);
1547         return -1;
1548         }
1549     td->dirPrice[i].priceNightA /= (1024*1024);
1550
1551     strprintf(&param, "PriceNightB%d", i);
1552     if (GetDouble(row[4+i*8], &td->dirPrice[i].priceNightB, 0.0) < 0)
1553         {
1554         mysql_free_result(res);
1555         errorStr = "Cannot read tariff " + tariffName + ". Parameter " + param;
1556         mysql_close(sock);
1557         return -1;
1558         }
1559     td->dirPrice[i].priceNightB /= (1024*1024);
1560
1561     strprintf(&param, "Threshold%d", i);
1562     if (GetInt(row[5+i*8], &td->dirPrice[i].threshold) < 0)
1563         {
1564         mysql_free_result(res);
1565         errorStr = "Cannot read tariff " + tariffName + ". Parameter " + param;
1566         mysql_close(sock);
1567         return -1;
1568         }
1569
1570     strprintf(&param, "SinglePrice%d", i);
1571     if (GetInt(row[8+i*8], &td->dirPrice[i].singlePrice) < 0)
1572         {
1573         mysql_free_result(res);
1574         errorStr = "Cannot read tariff " + tariffName + ". Parameter " + param;
1575         mysql_close(sock);
1576         return -1;
1577         }
1578
1579     strprintf(&param, "NoDiscount%d", i);
1580     if (GetInt(row[7+i*8], &td->dirPrice[i].noDiscount) < 0)
1581         {
1582         mysql_free_result(res);
1583         errorStr = "Cannot read tariff " + tariffName + ". Parameter " + param;
1584         mysql_close(sock);
1585         return -1;
1586         }
1587     }//main for
1588
1589 if (GetDouble(row[2+8*DIR_NUM], &td->tariffConf.fee, 0.0) < 0)
1590     {
1591     mysql_free_result(res);
1592     errorStr = "Cannot read tariff " + tariffName + ". Parameter Fee";
1593     mysql_close(sock);
1594     return -1;
1595     }
1596
1597 if (GetDouble(row[3+8*DIR_NUM], &td->tariffConf.free, 0.0) < 0)
1598     {
1599     mysql_free_result(res);
1600     errorStr = "Cannot read tariff " + tariffName + ". Parameter Free";
1601     mysql_close(sock);
1602     return -1;
1603     }
1604
1605 if (GetDouble(row[1+8*DIR_NUM], &td->tariffConf.passiveCost, 0.0) < 0)
1606     {
1607     mysql_free_result(res);
1608     errorStr = "Cannot read tariff " + tariffName + ". Parameter PassiveCost";
1609     mysql_close(sock);
1610     return -1;
1611     }
1612
1613     str = row[4+8*DIR_NUM];
1614     param = "TraffType";
1615     
1616     if (str.length() == 0)
1617         {
1618         mysql_free_result(res);
1619         errorStr = "Cannot read tariff " + tariffName + ". Parameter " + param;
1620         mysql_close(sock);
1621         return -1;
1622         }
1623
1624 if (!strcasecmp(str.c_str(), "up"))
1625     td->tariffConf.traffType = TRAFF_UP;
1626 else
1627     if (!strcasecmp(str.c_str(), "down"))
1628         td->tariffConf.traffType = TRAFF_DOWN;
1629     else
1630         if (!strcasecmp(str.c_str(), "up+down"))
1631             td->tariffConf.traffType = TRAFF_UP_DOWN;
1632         else
1633             if (!strcasecmp(str.c_str(), "max"))
1634                 td->tariffConf.traffType = TRAFF_MAX;
1635             else
1636                 {
1637                 mysql_free_result(res);
1638                 errorStr = "Cannot read tariff " + tariffName + ". Parameter TraffType incorrect";
1639                 mysql_close(sock);
1640                 return -1;
1641                 }
1642
1643 if (schemaVersion > 0)
1644 {
1645     str = row[5+8*DIR_NUM];
1646     param = "Period";
1647
1648     if (str.length() == 0)
1649         {
1650         mysql_free_result(res);
1651         errorStr = "Cannot read tariff " + tariffName + ". Parameter " + param;
1652         mysql_close(sock);
1653         return -1;
1654         }
1655
1656     td->tariffConf.period = TARIFF::StringToPeriod(str);
1657     }
1658 else
1659     {
1660     td->tariffConf.period = TARIFF::MONTH;
1661     }
1662
1663 mysql_free_result(res);
1664 mysql_close(sock);
1665 return 0;
1666 }
1667 //-----------------------------------------------------------------------------
1668 int MYSQL_STORE::SaveTariff(const TARIFF_DATA & td, const std::string & tariffName) const
1669 {
1670 std::string param;
1671
1672 std::string res="UPDATE tariffs SET";
1673
1674 for (int i = 0; i < DIR_NUM; i++)
1675     {
1676     strprintf(&param, " PriceDayA%d=%f,", i, 
1677         td.dirPrice[i].priceDayA * pt_mega);
1678     res += param;
1679
1680     strprintf(&param, " PriceDayB%d=%f,", i, 
1681         td.dirPrice[i].priceDayB * pt_mega);        
1682     res += param;
1683         
1684     strprintf(&param, " PriceNightA%d=%f,", i,
1685         td.dirPrice[i].priceNightA * pt_mega);
1686     res += param;
1687
1688     strprintf(&param, " PriceNightB%d=%f,", i, 
1689         td.dirPrice[i].priceNightB * pt_mega);
1690     res += param;
1691         
1692     strprintf(&param, " Threshold%d=%d,", i, 
1693         td.dirPrice[i].threshold);
1694     res += param;
1695
1696     std::string s;
1697     strprintf(&param, " Time%d", i);
1698
1699     strprintf(&s, "%0d:%0d-%0d:%0d", 
1700             td.dirPrice[i].hDay,
1701             td.dirPrice[i].mDay,
1702             td.dirPrice[i].hNight,
1703             td.dirPrice[i].mNight);
1704
1705     res += (param + "='" + s + "',");
1706
1707     strprintf(&param, " NoDiscount%d=%d,", i, 
1708         td.dirPrice[i].noDiscount);
1709     res += param;
1710
1711     strprintf(&param, " SinglePrice%d=%d,", i, 
1712         td.dirPrice[i].singlePrice);
1713     res += param;
1714     }
1715
1716 strprintf(&param, " PassiveCost=%f,", td.tariffConf.passiveCost);
1717 res += param;
1718
1719 strprintf(&param, " Fee=%f,", td.tariffConf.fee);
1720 res += param;
1721
1722 strprintf(&param, " Free=%f,", td.tariffConf.free);
1723 res += param;
1724
1725 switch (td.tariffConf.traffType)
1726     {
1727     case TRAFF_UP:
1728         res += " TraffType='up'";
1729         break;
1730     case TRAFF_DOWN:
1731         res += " TraffType='down'";
1732         break;
1733     case TRAFF_UP_DOWN:
1734         res += " TraffType='up+down'";
1735         break;
1736     case TRAFF_MAX:
1737         res += " TraffType='max'";
1738         break;
1739     }
1740
1741 if (schemaVersion > 0)
1742     res += ", Period='" + TARIFF::PeriodToString(td.tariffConf.period) + "'";
1743
1744 strprintf(&param, " WHERE name='%s' LIMIT 1", tariffName.c_str());
1745 res += param;
1746
1747 if(MysqlSetQuery(res.c_str()))
1748 {
1749     errorStr = "Couldn't save tariff:\n";
1750     //errorStr += mysql_error(sock);
1751     return -1;
1752 }
1753
1754 return 0;
1755 }
1756 //-----------------------------------------------------------------------------
1757 int MYSQL_STORE::WriteDetailedStat(const std::map<IP_DIR_PAIR, STAT_NODE> & statTree, 
1758                                    time_t lastStat, 
1759                                    const std::string & login) const
1760 {
1761 std::string res, stTime, endTime, tempStr;
1762 time_t t;
1763 tm * lt;
1764
1765 t = time(NULL);
1766 lt = localtime(&t);
1767
1768 if (lt->tm_hour == 0 && lt->tm_min <= 5)
1769     {
1770         t -= 3600 * 24;
1771         lt = localtime(&t);
1772     }
1773
1774 MYSQL_RES* result;
1775 MYSQL * sock;
1776 strprintf(&tempStr, "detailstat_%02d_%4d", lt->tm_mon+1, lt->tm_year+1900);
1777
1778 if (!(sock=MysqlConnect())){
1779     mysql_close(sock);
1780     return -1;
1781 }
1782
1783 if (!(result=mysql_list_tables(sock,tempStr.c_str() )))
1784 {
1785     errorStr = "Couldn't get table " + tempStr + ":\n";
1786     errorStr += mysql_error(sock);
1787     mysql_close(sock);
1788     return -1;
1789 }
1790
1791 my_ulonglong num_rows =  mysql_num_rows(result);
1792
1793 mysql_free_result(result);
1794
1795 if (num_rows < 1)
1796 {
1797     sprintf(qbuf,"CREATE TABLE detailstat_%02d_%4d (login VARCHAR(40) DEFAULT '',"\
1798         "day TINYINT DEFAULT 0,startTime TIME,endTime TIME,"\
1799         "IP VARCHAR(17) DEFAULT '',dir INT DEFAULT 0,"\
1800         "down BIGINT DEFAULT 0,up BIGINT DEFAULT 0, cash DOUBLE DEFAULT 0.0, INDEX (login), INDEX(dir), INDEX(day), INDEX(IP))",
1801     lt->tm_mon+1, lt->tm_year+1900);
1802     
1803     if(MysqlQuery(qbuf,sock))
1804     {
1805         errorStr = "Couldn't create WriteDetailedStat table:\n";
1806         errorStr += mysql_error(sock);
1807         mysql_close(sock);
1808         return -1;
1809     }
1810 }
1811
1812 struct tm * lt1;
1813 struct tm * lt2;
1814
1815 lt1 = localtime(&lastStat);
1816
1817 int h1, m1, s1;
1818 int h2, m2, s2;
1819
1820 h1 = lt1->tm_hour;
1821 m1 = lt1->tm_min;
1822 s1 = lt1->tm_sec;
1823
1824 lt2 = localtime(&t);
1825
1826 h2 = lt2->tm_hour;
1827 m2 = lt2->tm_min;
1828 s2 = lt2->tm_sec;
1829     
1830 strprintf(&stTime, "%02d:%02d:%02d", h1, m1, s1);
1831 strprintf(&endTime, "%02d:%02d:%02d", h2, m2, s2);
1832
1833 strprintf(&res,"INSERT INTO detailstat_%02d_%4d SET login='%s',"\
1834     "day=%d,startTime='%s',endTime='%s',", 
1835     lt->tm_mon+1, lt->tm_year+1900,
1836     login.c_str(),
1837     lt->tm_mday,
1838     stTime.c_str(),
1839     endTime.c_str()
1840     );
1841
1842 std::map<IP_DIR_PAIR, STAT_NODE>::const_iterator stIter;
1843 stIter = statTree.begin();
1844
1845 while (stIter != statTree.end())
1846     {
1847         strprintf(&tempStr,"IP='%s', dir=%d, down=%lld, up=%lld, cash=%f", 
1848                 inet_ntostring(stIter->first.ip).c_str(),
1849                 stIter->first.dir, 
1850                 stIter->second.down, 
1851                 stIter->second.up, 
1852                 stIter->second.cash
1853             );
1854     
1855         if( MysqlQuery((res+tempStr).c_str(),sock) )
1856         {
1857             errorStr = "Couldn't insert data in WriteDetailedStat:\n";
1858             errorStr += mysql_error(sock);
1859             mysql_close(sock);
1860             return -1;
1861         }
1862
1863         result=mysql_store_result(sock);
1864         if(result)
1865             mysql_free_result(result);
1866
1867         ++stIter;
1868     }
1869 mysql_close(sock);
1870 return 0;
1871 }
1872 //-----------------------------------------------------------------------------
1873 int MYSQL_STORE::AddMessage(STG_MSG * msg, const std::string & login) const
1874 {
1875 struct timeval tv;
1876
1877 gettimeofday(&tv, NULL);
1878
1879 msg->header.id = static_cast<uint64_t>(tv.tv_sec) * 1000000 + static_cast<uint64_t>(tv.tv_usec);
1880
1881 sprintf(qbuf,"INSERT INTO messages SET login='%s', id=%lld", 
1882     login.c_str(),
1883     static_cast<long long>(msg->header.id)
1884     );
1885     
1886 if(MysqlSetQuery(qbuf))
1887 {
1888     errorStr = "Couldn't add message:\n";
1889     //errorStr += mysql_error(sock);
1890     return -1;
1891 }
1892
1893 return EditMessage(*msg, login);
1894 }
1895 //-----------------------------------------------------------------------------
1896 int MYSQL_STORE::EditMessage(const STG_MSG & msg, const std::string & login) const
1897 {
1898 std::string res;
1899
1900 strprintf(&res,"UPDATE messages SET type=%d, lastSendTime=%u, creationTime=%u, "\
1901     "showTime=%u, stgRepeat=%d, repeatPeriod=%u, text='%s' "\
1902     "WHERE login='%s' AND id=%lld LIMIT 1", 
1903     msg.header.type,
1904     msg.header.lastSendTime,
1905     msg.header.creationTime,
1906     msg.header.showTime,
1907     msg.header.repeat,
1908     msg.header.repeatPeriod,
1909     (ReplaceStr(msg.text,badSyms,repSym)).c_str(),
1910     login.c_str(),
1911     msg.header.id
1912     );
1913
1914 if(MysqlSetQuery(res.c_str()))
1915 {
1916     errorStr = "Couldn't edit message:\n";
1917     //errorStr += mysql_error(sock);
1918     return -1;
1919 }
1920
1921 return 0;
1922 }
1923 //-----------------------------------------------------------------------------
1924 int MYSQL_STORE::GetMessage(uint64_t id, STG_MSG * msg, const std::string & login) const
1925 {
1926 MYSQL_RES *res;
1927 MYSQL_ROW row;
1928 MYSQL * sock;
1929
1930 sprintf(qbuf,"SELECT * FROM messages WHERE login='%s' AND id=%llu LIMIT 1",
1931         login.c_str(), static_cast<unsigned long long>(id));
1932     
1933 if(MysqlGetQuery(qbuf,sock))
1934 {
1935     errorStr = "Couldn't GetMessage:\n";
1936     errorStr += mysql_error(sock);
1937     mysql_close(sock);
1938     return -1;
1939 }
1940
1941 if (!(res=mysql_store_result(sock)))
1942 {
1943     errorStr = "Couldn't GetMessage:\n";
1944     errorStr += mysql_error(sock);
1945     mysql_close(sock);
1946     return -1;
1947 }
1948
1949 row = mysql_fetch_row(res);
1950
1951 if(row[2]&&str2x(row[2], msg->header.type))
1952 {
1953     mysql_free_result(res);
1954     errorStr = "Invalid value in message header for user: " + login;
1955     mysql_close(sock);
1956     return -1;
1957 }
1958
1959 if(row[3] && str2x(row[3], msg->header.lastSendTime))
1960 {
1961     mysql_free_result(res);
1962     errorStr = "Invalid value in message header for user: " + login;
1963     mysql_close(sock);
1964     return -1;
1965 }
1966
1967 if(row[4] && str2x(row[4], msg->header.creationTime))
1968 {
1969     mysql_free_result(res);
1970     errorStr = "Invalid value in message header for user: " + login;
1971     mysql_close(sock);
1972     return -1;
1973 }
1974
1975 if(row[5] && str2x(row[5], msg->header.showTime))
1976 {
1977     mysql_free_result(res);
1978     errorStr = "Invalid value in message header for user: " + login;
1979     mysql_close(sock);
1980     return -1;
1981 }
1982
1983 if(row[6] && str2x(row[6], msg->header.repeat))
1984 {
1985     mysql_free_result(res);
1986     errorStr = "Invalid value in message header for user: " + login;
1987     mysql_close(sock);
1988     return -1;
1989 }
1990
1991 if(row[7] && str2x(row[7], msg->header.repeatPeriod))
1992 {
1993     mysql_free_result(res);
1994     errorStr = "Invalid value in message header for user: " + login;
1995     mysql_close(sock);
1996     return -1;
1997 }
1998
1999 msg->header.id = id;
2000 msg->text = row[8];
2001
2002 mysql_free_result(res);
2003 mysql_close(sock);
2004 return 0;
2005 }
2006 //-----------------------------------------------------------------------------
2007 int MYSQL_STORE::DelMessage(uint64_t id, const std::string & login) const
2008 {
2009 sprintf(qbuf,"DELETE FROM messages WHERE login='%s' AND id=%lld LIMIT 1", 
2010         login.c_str(), static_cast<long long>(id));
2011     
2012 if(MysqlSetQuery(qbuf))
2013 {
2014     errorStr = "Couldn't delete Message:\n";
2015     //errorStr += mysql_error(sock);
2016     return -1;
2017 }
2018
2019 return 0;
2020 }
2021 //-----------------------------------------------------------------------------
2022 int MYSQL_STORE::GetMessageHdrs(std::vector<STG_MSG_HDR> * hdrsList, const std::string & login) const
2023 {
2024 MYSQL_RES *res;
2025 MYSQL_ROW row;
2026 MYSQL * sock;
2027 sprintf(qbuf,"SELECT * FROM messages WHERE login='%s'", login.c_str());
2028     
2029 if(MysqlGetQuery(qbuf,sock))
2030 {
2031     errorStr = "Couldn't GetMessageHdrs:\n";
2032     errorStr += mysql_error(sock);
2033     mysql_close(sock);
2034     return -1;
2035 }
2036
2037 if (!(res=mysql_store_result(sock)))
2038 {
2039     errorStr = "Couldn't GetMessageHdrs:\n";
2040     errorStr += mysql_error(sock);
2041     mysql_close(sock);
2042     return -1;
2043 }
2044
2045 unsigned int i;
2046 my_ulonglong num_rows = mysql_num_rows(res);
2047 uint64_t id = 0;
2048
2049 for (i = 0; i < num_rows; i++)
2050 {
2051     row = mysql_fetch_row(res);
2052     if (str2x(row[1], id))
2053         continue;
2054     
2055     STG_MSG_HDR hdr;
2056     if (row[2]) 
2057         if(str2x(row[2], hdr.type))
2058             continue;
2059
2060     if (row[3])
2061         if(str2x(row[3], hdr.lastSendTime))
2062             continue;
2063
2064     if (row[4])
2065         if(str2x(row[4], hdr.creationTime))
2066             continue;
2067
2068     if (row[5])
2069         if(str2x(row[5], hdr.showTime))
2070             continue;
2071
2072     if (row[6])
2073         if(str2x(row[6], hdr.repeat))
2074             continue;
2075
2076     if (row[7])
2077         if(str2x(row[7], hdr.repeatPeriod))
2078             continue;
2079
2080     hdr.id = id;
2081     hdrsList->push_back(hdr);
2082 }
2083
2084 mysql_free_result(res);
2085 mysql_close(sock);
2086 return 0;
2087 }
2088 //-----------------------------------------------------------------------------
2089
2090 int MYSQL_STORE::MysqlSetQuery(const char * Query) const {
2091
2092     MYSQL * sock;
2093     int ret=MysqlGetQuery(Query,sock);
2094     mysql_close(sock);
2095     return ret;
2096 }
2097 //-----------------------------------------------------------------------------
2098 int  MYSQL_STORE::MysqlGetQuery(const char * Query,MYSQL * & sock) const {
2099     if (!(sock=MysqlConnect())) {
2100         return -1;
2101     }
2102     return   MysqlQuery(Query,sock);
2103 }
2104 //-----------------------------------------------------------------------------
2105 MYSQL *  MYSQL_STORE::MysqlConnect() const {
2106     MYSQL * sock;
2107     if ( !(sock=mysql_init(NULL)) ){
2108         errorStr= "mysql init susck\n";
2109         return NULL;
2110     }
2111     if (!(sock = mysql_real_connect(sock,storeSettings.GetDBHost().c_str(),
2112             storeSettings.GetDBUser().c_str(),storeSettings.GetDBPassword().c_str(),
2113             0,0,NULL,0)))
2114         {
2115             errorStr = "Couldn't connect to mysql engine! With error:\n";
2116             errorStr += mysql_error(sock);
2117             return NULL;
2118         }
2119     else{
2120          if(mysql_select_db(sock, storeSettings.GetDBName().c_str())){
2121              errorStr = "Database lost !\n";
2122              return NULL;
2123          }
2124     }
2125     return sock;
2126 }
2127 //-----------------------------------------------------------------------------