]> git.stg.codes - stg.git/blob - projects/stargazer/plugins/store/mysql/mysql_store.cpp
Optimized sending answers in sgconfig.
[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 EnDecodeInit(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     EncodeString(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     EnDecodeInit(adm_enc_passwd, strlen(adm_enc_passwd), &ctx);
1360
1361     for (int i = 0; i < ADM_PASSWD_LEN/8; i++)
1362         {
1363         DecodeString(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 if (!strcasecmp(str.c_str(), "up"))
1629     td->tariffConf.traffType = TRAFF_UP;
1630 else
1631     if (!strcasecmp(str.c_str(), "down"))
1632         td->tariffConf.traffType = TRAFF_DOWN;
1633     else
1634         if (!strcasecmp(str.c_str(), "up+down"))
1635             td->tariffConf.traffType = TRAFF_UP_DOWN;
1636         else
1637             if (!strcasecmp(str.c_str(), "max"))
1638                 td->tariffConf.traffType = TRAFF_MAX;
1639             else
1640                 {
1641                 mysql_free_result(res);
1642                 errorStr = "Cannot read tariff " + tariffName + ". Parameter TraffType incorrect";
1643                 mysql_close(sock);
1644                 return -1;
1645                 }
1646
1647 if (schemaVersion > 0)
1648 {
1649     str = row[5+8*DIR_NUM];
1650     param = "Period";
1651
1652     if (str.length() == 0)
1653         {
1654         mysql_free_result(res);
1655         errorStr = "Cannot read tariff " + tariffName + ". Parameter " + param;
1656         mysql_close(sock);
1657         return -1;
1658         }
1659
1660     td->tariffConf.period = TARIFF::StringToPeriod(str);
1661     }
1662 else
1663     {
1664     td->tariffConf.period = TARIFF::MONTH;
1665     }
1666
1667 mysql_free_result(res);
1668 mysql_close(sock);
1669 return 0;
1670 }
1671 //-----------------------------------------------------------------------------
1672 int MYSQL_STORE::SaveTariff(const TARIFF_DATA & td, const std::string & tariffName) const
1673 {
1674 std::string param;
1675
1676 std::string res="UPDATE tariffs SET";
1677
1678 for (int i = 0; i < DIR_NUM; i++)
1679     {
1680     strprintf(&param, " PriceDayA%d=%f,", i, 
1681         td.dirPrice[i].priceDayA * pt_mega);
1682     res += param;
1683
1684     strprintf(&param, " PriceDayB%d=%f,", i, 
1685         td.dirPrice[i].priceDayB * pt_mega);        
1686     res += param;
1687         
1688     strprintf(&param, " PriceNightA%d=%f,", i,
1689         td.dirPrice[i].priceNightA * pt_mega);
1690     res += param;
1691
1692     strprintf(&param, " PriceNightB%d=%f,", i, 
1693         td.dirPrice[i].priceNightB * pt_mega);
1694     res += param;
1695         
1696     strprintf(&param, " Threshold%d=%d,", i, 
1697         td.dirPrice[i].threshold);
1698     res += param;
1699
1700     std::string s;
1701     strprintf(&param, " Time%d", i);
1702
1703     strprintf(&s, "%0d:%0d-%0d:%0d", 
1704             td.dirPrice[i].hDay,
1705             td.dirPrice[i].mDay,
1706             td.dirPrice[i].hNight,
1707             td.dirPrice[i].mNight);
1708
1709     res += (param + "='" + s + "',");
1710
1711     strprintf(&param, " NoDiscount%d=%d,", i, 
1712         td.dirPrice[i].noDiscount);
1713     res += param;
1714
1715     strprintf(&param, " SinglePrice%d=%d,", i, 
1716         td.dirPrice[i].singlePrice);
1717     res += param;
1718     }
1719
1720 strprintf(&param, " PassiveCost=%f,", td.tariffConf.passiveCost);
1721 res += param;
1722
1723 strprintf(&param, " Fee=%f,", td.tariffConf.fee);
1724 res += param;
1725
1726 strprintf(&param, " Free=%f,", td.tariffConf.free);
1727 res += param;
1728
1729 switch (td.tariffConf.traffType)
1730     {
1731     case TRAFF_UP:
1732         res += " TraffType='up'";
1733         break;
1734     case TRAFF_DOWN:
1735         res += " TraffType='down'";
1736         break;
1737     case TRAFF_UP_DOWN:
1738         res += " TraffType='up+down'";
1739         break;
1740     case TRAFF_MAX:
1741         res += " TraffType='max'";
1742         break;
1743     }
1744
1745 if (schemaVersion > 0)
1746     res += ", Period='" + TARIFF::PeriodToString(td.tariffConf.period) + "'";
1747
1748 strprintf(&param, " WHERE name='%s' LIMIT 1", tariffName.c_str());
1749 res += param;
1750
1751 if(MysqlSetQuery(res.c_str()))
1752 {
1753     errorStr = "Couldn't save tariff:\n";
1754     //errorStr += mysql_error(sock);
1755     return -1;
1756 }
1757
1758 return 0;
1759 }
1760 //-----------------------------------------------------------------------------
1761 int MYSQL_STORE::WriteDetailedStat(const std::map<IP_DIR_PAIR, STAT_NODE> & statTree, 
1762                                    time_t lastStat, 
1763                                    const std::string & login) const
1764 {
1765 std::string res, stTime, endTime, tempStr;
1766 time_t t;
1767 tm * lt;
1768
1769 t = time(NULL);
1770 lt = localtime(&t);
1771
1772 if (lt->tm_hour == 0 && lt->tm_min <= 5)
1773     {
1774         t -= 3600 * 24;
1775         lt = localtime(&t);
1776     }
1777
1778 MYSQL_RES* result;
1779 MYSQL * sock;
1780 strprintf(&tempStr, "detailstat_%02d_%4d", lt->tm_mon+1, lt->tm_year+1900);
1781
1782 if (!(sock=MysqlConnect())){
1783     mysql_close(sock);
1784     return -1;
1785 }
1786
1787 if (!(result=mysql_list_tables(sock,tempStr.c_str() )))
1788 {
1789     errorStr = "Couldn't get table " + tempStr + ":\n";
1790     errorStr += mysql_error(sock);
1791     mysql_close(sock);
1792     return -1;
1793 }
1794
1795 my_ulonglong num_rows =  mysql_num_rows(result);
1796
1797 mysql_free_result(result);
1798
1799 if (num_rows < 1)
1800 {
1801     sprintf(qbuf,"CREATE TABLE detailstat_%02d_%4d (login VARCHAR(40) DEFAULT '',"\
1802         "day TINYINT DEFAULT 0,startTime TIME,endTime TIME,"\
1803         "IP VARCHAR(17) DEFAULT '',dir INT DEFAULT 0,"\
1804         "down BIGINT DEFAULT 0,up BIGINT DEFAULT 0, cash DOUBLE DEFAULT 0.0, INDEX (login), INDEX(dir), INDEX(day), INDEX(IP))",
1805     lt->tm_mon+1, lt->tm_year+1900);
1806     
1807     if(MysqlQuery(qbuf,sock))
1808     {
1809         errorStr = "Couldn't create WriteDetailedStat table:\n";
1810         errorStr += mysql_error(sock);
1811         mysql_close(sock);
1812         return -1;
1813     }
1814 }
1815
1816 struct tm * lt1;
1817 struct tm * lt2;
1818
1819 lt1 = localtime(&lastStat);
1820
1821 int h1, m1, s1;
1822 int h2, m2, s2;
1823
1824 h1 = lt1->tm_hour;
1825 m1 = lt1->tm_min;
1826 s1 = lt1->tm_sec;
1827
1828 lt2 = localtime(&t);
1829
1830 h2 = lt2->tm_hour;
1831 m2 = lt2->tm_min;
1832 s2 = lt2->tm_sec;
1833     
1834 strprintf(&stTime, "%02d:%02d:%02d", h1, m1, s1);
1835 strprintf(&endTime, "%02d:%02d:%02d", h2, m2, s2);
1836
1837 strprintf(&res,"INSERT INTO detailstat_%02d_%4d SET login='%s',"\
1838     "day=%d,startTime='%s',endTime='%s',", 
1839     lt->tm_mon+1, lt->tm_year+1900,
1840     login.c_str(),
1841     lt->tm_mday,
1842     stTime.c_str(),
1843     endTime.c_str()
1844     );
1845
1846 std::map<IP_DIR_PAIR, STAT_NODE>::const_iterator stIter;
1847 stIter = statTree.begin();
1848
1849 while (stIter != statTree.end())
1850     {
1851         strprintf(&tempStr,"IP='%s', dir=%d, down=%lld, up=%lld, cash=%f", 
1852                 inet_ntostring(stIter->first.ip).c_str(),
1853                 stIter->first.dir, 
1854                 stIter->second.down, 
1855                 stIter->second.up, 
1856                 stIter->second.cash
1857             );
1858     
1859         if( MysqlQuery((res+tempStr).c_str(),sock) )
1860         {
1861             errorStr = "Couldn't insert data in WriteDetailedStat:\n";
1862             errorStr += mysql_error(sock);
1863             mysql_close(sock);
1864             return -1;
1865         }
1866
1867         result=mysql_store_result(sock);
1868         if(result)
1869             mysql_free_result(result);
1870
1871         ++stIter;
1872     }
1873 mysql_close(sock);
1874 return 0;
1875 }
1876 //-----------------------------------------------------------------------------
1877 int MYSQL_STORE::AddMessage(STG_MSG * msg, const std::string & login) const
1878 {
1879 struct timeval tv;
1880
1881 gettimeofday(&tv, NULL);
1882
1883 msg->header.id = static_cast<uint64_t>(tv.tv_sec) * 1000000 + static_cast<uint64_t>(tv.tv_usec);
1884
1885 sprintf(qbuf,"INSERT INTO messages SET login='%s', id=%lld", 
1886     login.c_str(),
1887     static_cast<long long>(msg->header.id)
1888     );
1889     
1890 if(MysqlSetQuery(qbuf))
1891 {
1892     errorStr = "Couldn't add message:\n";
1893     //errorStr += mysql_error(sock);
1894     return -1;
1895 }
1896
1897 return EditMessage(*msg, login);
1898 }
1899 //-----------------------------------------------------------------------------
1900 int MYSQL_STORE::EditMessage(const STG_MSG & msg, const std::string & login) const
1901 {
1902 std::string res;
1903
1904 strprintf(&res,"UPDATE messages SET type=%d, lastSendTime=%u, creationTime=%u, "\
1905     "showTime=%u, stgRepeat=%d, repeatPeriod=%u, text='%s' "\
1906     "WHERE login='%s' AND id=%lld LIMIT 1", 
1907     msg.header.type,
1908     msg.header.lastSendTime,
1909     msg.header.creationTime,
1910     msg.header.showTime,
1911     msg.header.repeat,
1912     msg.header.repeatPeriod,
1913     (ReplaceStr(msg.text,badSyms,repSym)).c_str(),
1914     login.c_str(),
1915     msg.header.id
1916     );
1917
1918 if(MysqlSetQuery(res.c_str()))
1919 {
1920     errorStr = "Couldn't edit message:\n";
1921     //errorStr += mysql_error(sock);
1922     return -1;
1923 }
1924
1925 return 0;
1926 }
1927 //-----------------------------------------------------------------------------
1928 int MYSQL_STORE::GetMessage(uint64_t id, STG_MSG * msg, const std::string & login) const
1929 {
1930 MYSQL_RES *res;
1931 MYSQL_ROW row;
1932 MYSQL * sock;
1933
1934 sprintf(qbuf,"SELECT * FROM messages WHERE login='%s' AND id=%llu LIMIT 1",
1935         login.c_str(), static_cast<unsigned long long>(id));
1936     
1937 if(MysqlGetQuery(qbuf,sock))
1938 {
1939     errorStr = "Couldn't GetMessage:\n";
1940     errorStr += mysql_error(sock);
1941     mysql_close(sock);
1942     return -1;
1943 }
1944
1945 if (!(res=mysql_store_result(sock)))
1946 {
1947     errorStr = "Couldn't GetMessage:\n";
1948     errorStr += mysql_error(sock);
1949     mysql_close(sock);
1950     return -1;
1951 }
1952
1953 row = mysql_fetch_row(res);
1954
1955 if(row[2]&&str2x(row[2], msg->header.type))
1956 {
1957     mysql_free_result(res);
1958     errorStr = "Invalid value in message header for user: " + login;
1959     mysql_close(sock);
1960     return -1;
1961 }
1962
1963 if(row[3] && str2x(row[3], msg->header.lastSendTime))
1964 {
1965     mysql_free_result(res);
1966     errorStr = "Invalid value in message header for user: " + login;
1967     mysql_close(sock);
1968     return -1;
1969 }
1970
1971 if(row[4] && str2x(row[4], msg->header.creationTime))
1972 {
1973     mysql_free_result(res);
1974     errorStr = "Invalid value in message header for user: " + login;
1975     mysql_close(sock);
1976     return -1;
1977 }
1978
1979 if(row[5] && str2x(row[5], msg->header.showTime))
1980 {
1981     mysql_free_result(res);
1982     errorStr = "Invalid value in message header for user: " + login;
1983     mysql_close(sock);
1984     return -1;
1985 }
1986
1987 if(row[6] && str2x(row[6], msg->header.repeat))
1988 {
1989     mysql_free_result(res);
1990     errorStr = "Invalid value in message header for user: " + login;
1991     mysql_close(sock);
1992     return -1;
1993 }
1994
1995 if(row[7] && str2x(row[7], msg->header.repeatPeriod))
1996 {
1997     mysql_free_result(res);
1998     errorStr = "Invalid value in message header for user: " + login;
1999     mysql_close(sock);
2000     return -1;
2001 }
2002
2003 msg->header.id = id;
2004 msg->text = row[8];
2005
2006 mysql_free_result(res);
2007 mysql_close(sock);
2008 return 0;
2009 }
2010 //-----------------------------------------------------------------------------
2011 int MYSQL_STORE::DelMessage(uint64_t id, const std::string & login) const
2012 {
2013 sprintf(qbuf,"DELETE FROM messages WHERE login='%s' AND id=%lld LIMIT 1", 
2014         login.c_str(), static_cast<long long>(id));
2015     
2016 if(MysqlSetQuery(qbuf))
2017 {
2018     errorStr = "Couldn't delete Message:\n";
2019     //errorStr += mysql_error(sock);
2020     return -1;
2021 }
2022
2023 return 0;
2024 }
2025 //-----------------------------------------------------------------------------
2026 int MYSQL_STORE::GetMessageHdrs(std::vector<STG_MSG_HDR> * hdrsList, const std::string & login) const
2027 {
2028 MYSQL_RES *res;
2029 MYSQL_ROW row;
2030 MYSQL * sock;
2031 sprintf(qbuf,"SELECT * FROM messages WHERE login='%s'", login.c_str());
2032     
2033 if(MysqlGetQuery(qbuf,sock))
2034 {
2035     errorStr = "Couldn't GetMessageHdrs:\n";
2036     errorStr += mysql_error(sock);
2037     mysql_close(sock);
2038     return -1;
2039 }
2040
2041 if (!(res=mysql_store_result(sock)))
2042 {
2043     errorStr = "Couldn't GetMessageHdrs:\n";
2044     errorStr += mysql_error(sock);
2045     mysql_close(sock);
2046     return -1;
2047 }
2048
2049 unsigned int i;
2050 my_ulonglong num_rows = mysql_num_rows(res);
2051 uint64_t id = 0;
2052
2053 for (i = 0; i < num_rows; i++)
2054 {
2055     row = mysql_fetch_row(res);
2056     if (str2x(row[1], id))
2057         continue;
2058     
2059     STG_MSG_HDR hdr;
2060     if (row[2]) 
2061         if(str2x(row[2], hdr.type))
2062             continue;
2063
2064     if (row[3])
2065         if(str2x(row[3], hdr.lastSendTime))
2066             continue;
2067
2068     if (row[4])
2069         if(str2x(row[4], hdr.creationTime))
2070             continue;
2071
2072     if (row[5])
2073         if(str2x(row[5], hdr.showTime))
2074             continue;
2075
2076     if (row[6])
2077         if(str2x(row[6], hdr.repeat))
2078             continue;
2079
2080     if (row[7])
2081         if(str2x(row[7], hdr.repeatPeriod))
2082             continue;
2083
2084     hdr.id = id;
2085     hdrsList->push_back(hdr);
2086 }
2087
2088 mysql_free_result(res);
2089 mysql_close(sock);
2090 return 0;
2091 }
2092 //-----------------------------------------------------------------------------
2093
2094 int MYSQL_STORE::MysqlSetQuery(const char * Query) const {
2095
2096     MYSQL * sock;
2097     int ret=MysqlGetQuery(Query,sock);
2098     mysql_close(sock);
2099     return ret;
2100 }
2101 //-----------------------------------------------------------------------------
2102 int  MYSQL_STORE::MysqlGetQuery(const char * Query,MYSQL * & sock) const {
2103     if (!(sock=MysqlConnect())) {
2104         return -1;
2105     }
2106     return   MysqlQuery(Query,sock);
2107 }
2108 //-----------------------------------------------------------------------------
2109 MYSQL *  MYSQL_STORE::MysqlConnect() const {
2110     MYSQL * sock;
2111     if ( !(sock=mysql_init(NULL)) ){
2112         errorStr= "mysql init susck\n";
2113         return NULL;
2114     }
2115     if (!(sock = mysql_real_connect(sock,storeSettings.GetDBHost().c_str(),
2116             storeSettings.GetDBUser().c_str(),storeSettings.GetDBPassword().c_str(),
2117             0,0,NULL,0)))
2118         {
2119             errorStr = "Couldn't connect to mysql engine! With error:\n";
2120             errorStr += mysql_error(sock);
2121             return NULL;
2122         }
2123     else{
2124          if(mysql_select_db(sock, storeSettings.GetDBName().c_str())){
2125              errorStr = "Database lost !\n";
2126              return NULL;
2127          }
2128     }
2129     return sock;
2130 }
2131 //-----------------------------------------------------------------------------