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