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