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