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