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