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