]> git.stg.codes - stg.git/blob - projects/stargazer/plugins/configuration/sgconfig/parser.cpp
Merge branch 'fix-gts-auth-errors' into full-month-stats
[stg.git] / projects / stargazer / plugins / configuration / sgconfig / parser.cpp
1 #include <stdio.h>
2 #include <sys/utsname.h>
3 #include <sys/types.h>
4 #include <sys/socket.h>
5 #include <netinet/in.h>
6 #include <arpa/inet.h>
7
8 #include <cstring>
9 #include <cerrno>
10 #include <sstream>
11
12 #include "stg/version.h"
13 #include "stg/tariffs.h"
14 #include "stg/user_property.h"
15 #include "stg/settings.h"
16 #include "stg/logger.h"
17 #include "parser.h"
18
19 #define  UNAME_LEN      (256)
20 //-----------------------------------------------------------------------------
21 //  GET SERVER INFO
22 //-----------------------------------------------------------------------------
23 int PARSER_GET_SERVER_INFO::ParseStart(void *, const char *el, const char **)
24 {
25 answerList->erase(answerList->begin(), answerList->end());
26 if (strcasecmp(el, "GetServerInfo") == 0)
27     {
28     return 0;
29     }
30 return -1;
31 }
32 //-----------------------------------------------------------------------------
33 int PARSER_GET_SERVER_INFO::ParseEnd(void *, const char *el)
34 {
35 if (strcasecmp(el, "GetServerInfo") == 0)
36     {
37     CreateAnswer();
38     return 0;
39     }
40 return -1;
41 }
42 //-----------------------------------------------------------------------------
43 void PARSER_GET_SERVER_INFO::CreateAnswer()
44 {
45 char s[UNAME_LEN + 128];
46 char un[UNAME_LEN];
47 struct utsname utsn;
48
49 uname(&utsn);
50 un[0] = 0;
51
52 strcat(un, utsn.sysname);
53 strcat(un, " ");
54 strcat(un, utsn.release);
55 strcat(un, " ");
56 strcat(un, utsn.machine);
57 strcat(un, " ");
58 strcat(un, utsn.nodename);
59
60 //answerList->clear();
61 answerList->erase(answerList->begin(), answerList->end());
62 answerList->push_back("<ServerInfo>");
63
64 sprintf(s, "<version value=\"%s\"/>", SERVER_VERSION);
65 answerList->push_back(s);
66
67 sprintf(s, "<tariff_num value=\"%llu\"/>", static_cast<unsigned long long>(tariffs->Count()));
68 answerList->push_back(s);
69
70 sprintf(s, "<tariff value=\"%d\"/>", 2);
71 answerList->push_back(s);
72
73 sprintf(s, "<users_num value=\"%llu\"/>", static_cast<unsigned long long>(users->Count()));
74 answerList->push_back(s);
75
76 sprintf(s, "<uname value=\"%s\"/>", un);
77 answerList->push_back(s);
78
79 sprintf(s, "<dir_num value=\"%d\"/>", DIR_NUM);
80 answerList->push_back(s);
81
82 sprintf(s, "<day_fee value=\"%d\"/>", settings->GetDayFee());
83 answerList->push_back(s);
84
85 for (int i = 0; i< DIR_NUM; i++)
86     {
87     std::string dn2e;
88     Encode12str(dn2e, settings->GetDirName(i));
89     sprintf(s, "<dir_name_%d value=\"%s\"/>", i, dn2e.c_str());
90     answerList->push_back(s);
91     }
92
93 answerList->push_back("</ServerInfo>");
94 }
95 //-----------------------------------------------------------------------------
96 //  GET USER
97 //-----------------------------------------------------------------------------
98 int PARSER_GET_USER::ParseStart(void *, const char *el, const char **attr)
99 {
100 if (strcasecmp(el, "GetUser") == 0)
101     {
102     if (attr[0] && attr[1])
103         login = attr[1];
104     else
105         {
106         //login.clear();
107         login.erase(login.begin(), login.end());
108         return -1;
109         }
110     return 0;
111     }
112 return -1;
113 }
114 //-----------------------------------------------------------------------------
115 int PARSER_GET_USER::ParseEnd(void *, const char *el)
116 {
117 if (strcasecmp(el, "GetUser") == 0)
118     {
119     CreateAnswer();
120     return 0;
121     }
122 return -1;
123 }
124 //-----------------------------------------------------------------------------
125 void PARSER_GET_USER::CreateAnswer()
126 {
127 std::string s;
128 std::string enc;
129
130 USER_PTR u;
131
132 answerList->erase(answerList->begin(), answerList->end());
133
134 if (users->FindByName(login, &u))
135     {
136     s = "<user result=\"error\"/>";
137     answerList->push_back(s);
138     return;
139     }
140
141 s = "<user result=\"ok\">";
142 answerList->push_back(s);
143
144 s = "<login value=\"" + u->GetLogin() + "\"/>";
145 answerList->push_back(s);
146
147 if (currAdmin->GetPriv()->userConf || currAdmin->GetPriv()->userPasswd)
148     s = "<password value=\"" + u->GetProperty().password.Get() + "\" />";
149 else
150     s = "<password value=\"++++++\"/>";
151 answerList->push_back(s);
152
153 strprintf(&s, "<cash value=\"%f\" />", u->GetProperty().cash.Get());
154 answerList->push_back(s);
155
156 strprintf(&s, "<freemb value=\"%f\" />", u->GetProperty().freeMb.Get());
157 answerList->push_back(s);
158
159 strprintf(&s, "<credit value=\"%f\" />", u->GetProperty().credit.Get());
160 answerList->push_back(s);
161
162 if (u->GetProperty().nextTariff.Get() != "")
163     {
164     strprintf(&s, "<tariff value=\"%s/%s\" />",
165               u->GetProperty().tariffName.Get().c_str(),
166               u->GetProperty().nextTariff.Get().c_str());
167     }
168 else
169     {
170     strprintf(&s, "<tariff value=\"%s\" />",
171               u->GetProperty().tariffName.Get().c_str());
172     }
173
174 answerList->push_back(s);
175
176 Encode12str(enc, u->GetProperty().note);
177 s = "<note value=\"" + enc + "\" />";
178 answerList->push_back(s);
179
180 Encode12str(enc, u->GetProperty().phone);
181 s = "<phone value=\"" + enc + "\" />";
182 answerList->push_back(s);
183
184 Encode12str(enc, u->GetProperty().address);
185 s = "<address value=\"" + enc + "\" />";
186 answerList->push_back(s);
187
188 Encode12str(enc, u->GetProperty().email);
189 s = "<email value=\"" + enc + "\" />";
190 answerList->push_back(s);
191
192
193 std::vector<USER_PROPERTY_LOGGED<std::string> *> userdata;
194 userdata.push_back(u->GetProperty().userdata0.GetPointer());
195 userdata.push_back(u->GetProperty().userdata1.GetPointer());
196 userdata.push_back(u->GetProperty().userdata2.GetPointer());
197 userdata.push_back(u->GetProperty().userdata3.GetPointer());
198 userdata.push_back(u->GetProperty().userdata4.GetPointer());
199 userdata.push_back(u->GetProperty().userdata5.GetPointer());
200 userdata.push_back(u->GetProperty().userdata6.GetPointer());
201 userdata.push_back(u->GetProperty().userdata7.GetPointer());
202 userdata.push_back(u->GetProperty().userdata8.GetPointer());
203 userdata.push_back(u->GetProperty().userdata9.GetPointer());
204
205 std::string tmpI;
206 for (unsigned i = 0; i < userdata.size(); i++)
207     {
208     Encode12str(enc, userdata[i]->Get());
209     s = "<UserData" + x2str(i, tmpI) + " value=\"" + enc + "\" />";
210     answerList->push_back(s);
211     }
212
213 Encode12str(enc, u->GetProperty().realName);
214 s = "<name value=\"" + enc + "\" />";
215 answerList->push_back(s);
216
217 Encode12str(enc, u->GetProperty().group);
218 s = "<GROUP value=\"" + enc + "\" />";
219 answerList->push_back(s);
220
221 strprintf(&s, "<status value=\"%d\" />", u->GetConnected());
222 answerList->push_back(s);
223
224 strprintf(&s, "<aonline value=\"%d\" />", u->GetProperty().alwaysOnline.Get());
225 answerList->push_back(s);
226
227 strprintf(&s, "<currip value=\"%s\" />", inet_ntostring(u->GetCurrIP()).c_str());
228 answerList->push_back(s);
229
230 strprintf(&s, "<PingTime value=\"%lu\" />", u->GetPingTime());
231 answerList->push_back(s);
232
233 std::ostringstream sstr;
234 sstr << u->GetProperty().ips.Get();
235 strprintf(&s, "<ip value=\"%s\" />", sstr.str().c_str());
236 answerList->push_back(s);
237
238 char * ss;
239 ss = new char[DIR_NUM*25*4 + 50];
240 char st[50];
241 sprintf(ss, "<traff");
242 DIR_TRAFF upload;
243 DIR_TRAFF download;
244 download = u->GetProperty().down.Get();
245 upload = u->GetProperty().up.Get();
246
247 for (int j = 0; j < DIR_NUM; j++)
248     {
249     std::string s;
250     x2str(upload[j], s);
251     sprintf(st, " MU%d=\"%s\"", j, s.c_str());
252     strcat(ss, st);
253
254     x2str(download[j], s);
255     sprintf(st, " MD%d=\"%s\"", j, s.c_str());
256     strcat(ss, st);
257
258     sprintf(st, " SU%d=\"0\"", j);
259     strcat(ss, st);
260
261     sprintf(st, " SD%d=\"0\"", j);
262     strcat(ss, st);
263     }
264 strcat(ss, " />");
265 answerList->push_back(ss);
266 delete[] ss;
267
268 strprintf(&s, "<down value=\"%d\" />", u->GetProperty().disabled.Get());
269 answerList->push_back(s);
270
271 strprintf(&s, "<DisableDetailStat value=\"%d\" />", u->GetProperty().disabledDetailStat.Get());
272 answerList->push_back(s);
273
274 strprintf(&s, "<passive value=\"%d\" />", u->GetProperty().passive.Get());
275 answerList->push_back(s);
276
277 strprintf(&s, "<LastCash value=\"%f\" />", u->GetProperty().lastCashAdd.Get());
278 answerList->push_back(s);
279
280 strprintf(&s, "<LastTimeCash value=\"%ld\" />", u->GetProperty().lastCashAddTime.Get());
281 answerList->push_back(s);
282
283 strprintf(&s, "<LastActivityTime value=\"%ld\" />", u->GetProperty().lastActivityTime.Get());
284 answerList->push_back(s);
285
286 strprintf(&s, "<CreditExpire value=\"%ld\" />", u->GetProperty().creditExpire.Get());
287 answerList->push_back(s);
288
289 s = "<AuthorizedBy>";
290 std::vector<std::string> list(u->GetAuthorizers());
291 for (std::vector<std::string>::const_iterator it = list.begin(); it != list.end(); ++it)
292     s += "<Auth name=\"" + *it + "\">";
293 s += "</AuthorizedBy>";
294 answerList->push_back(s);
295
296 strprintf(&s, "</user>");
297 answerList->push_back(s);
298 }
299 //-----------------------------------------------------------------------------
300 //  GET USERS
301 //-----------------------------------------------------------------------------
302 int PARSER_GET_USERS::ParseStart(void *, const char *el, const char ** attr)
303 {
304 /*if (attr && *attr && *(attr+1))
305     {
306     printfd(__FILE__, "attr=%s %s\n", *attr, *(attr+1));
307     }
308 else
309     {
310     printfd(__FILE__, "attr = NULL\n");
311     }*/
312
313 lastUpdateFound = false;
314 if (strcasecmp(el, "GetUsers") == 0)
315     {
316     while (attr && *attr && *(attr+1))
317         {
318         if (strcasecmp(*attr, "LastUpdate") == 0)
319             {
320             if (str2x(*(attr+1), lastUserUpdateTime) == 0)
321                 {
322                 //printfd(__FILE__, "lastUserUpdateTime=%d\n", lastUserUpdateTime);
323                 lastUpdateFound = true;
324                 }
325             else
326                 {
327                 //printfd(__FILE__, "NO lastUserUpdateTime\n");
328                 }
329             }
330         ++attr;
331         }
332
333     return 0;
334     }
335 return -1;
336 }
337 //-----------------------------------------------------------------------------
338 int PARSER_GET_USERS::ParseEnd(void *, const char *el)
339 {
340 if (strcasecmp(el, "GetUsers") == 0)
341     {
342     CreateAnswer();
343     return 0;
344     }
345 return -1;
346 }
347 //-----------------------------------------------------------------------------
348 void PARSER_GET_USERS::CreateAnswer()
349 {
350 answerList->erase(answerList->begin(), answerList->end());
351
352 std::string s;
353 std::string userStart;
354 std::string traffStart;
355 std::string traffMiddle;
356 std::string traffFinish;
357 std::string middle;
358 std::string userFinish;
359
360
361 std::string enc;
362
363 USER_PTR u;
364
365 int h = users->OpenSearch();
366 if (!h)
367     {
368     printfd(__FILE__, "users->OpenSearch() error\n");
369     users->CloseSearch(h);
370     return;
371     }
372 std::string updateTime;
373 x2str(time(NULL), updateTime);
374
375 if (lastUpdateFound)
376     answerList->push_back("<Users LastUpdate=\"" + updateTime + "\">");
377 else
378     answerList->push_back("<Users>");
379
380 while (1)
381     {
382     if (users->SearchNext(h, &u))
383         {
384         break;
385         }
386     userStart = "<user login=\"" + u->GetLogin() + "\">";
387     middle = "";
388
389     if (u->GetProperty().password.ModificationTime() > lastUserUpdateTime)
390         {
391         if (currAdmin->GetPriv()->userConf || currAdmin->GetPriv()->userPasswd)
392             s = "<password value=\"" + u->GetProperty().password.Get() + "\" />";
393         else
394             s = "<password value=\"++++++\"/>";
395         middle += s;
396         }
397
398
399     if (u->GetProperty().cash.ModificationTime() > lastUserUpdateTime)
400         {
401         strprintf(&s, "<cash value=\"%f\" />", u->GetProperty().cash.Get());
402         middle += s;
403         //printfd(__FILE__, "cash value=\"%f\"\n", u->GetProperty().cash.Get());
404         }
405
406
407     if (u->GetProperty().freeMb.ModificationTime() > lastUserUpdateTime)
408         {
409         strprintf(&s, "<freemb value=\"%f\" />", u->GetProperty().freeMb.Get());
410         middle += s;
411         }
412
413     if (u->GetProperty().credit.ModificationTime() > lastUserUpdateTime)
414         {
415         strprintf(&s, "<credit value=\"%f\" />", u->GetProperty().credit.Get());
416         middle += s;
417         }
418
419     if (u->GetProperty().nextTariff.Get() != "")
420         {
421         if (u->GetProperty().tariffName.ModificationTime() > lastUserUpdateTime
422             || u->GetProperty().nextTariff.ModificationTime() > lastUserUpdateTime)
423             {
424             strprintf(&s, "<tariff value=\"%s/%s\" />",
425                       u->GetProperty().tariffName.Get().c_str(),
426                       u->GetProperty().nextTariff.Get().c_str());
427             middle += s;
428             }
429         }
430     else
431         {
432         if (u->GetProperty().tariffName.ModificationTime() > lastUserUpdateTime)
433             {
434             strprintf(&s, "<tariff value=\"%s\" />",
435                       u->GetProperty().tariffName.Get().c_str());
436             middle += s;
437             }
438         }
439
440     if (u->GetProperty().note.ModificationTime() > lastUserUpdateTime)
441         {
442         Encode12str(enc, u->GetProperty().note);
443         strprintf(&s, "<note value=\"%s\" />", enc.c_str());
444         middle += s;
445         }
446
447     if (u->GetProperty().phone.ModificationTime() > lastUserUpdateTime)
448         {
449         Encode12str(enc, u->GetProperty().phone);
450         strprintf(&s, "<phone value=\"%s\" />", enc.c_str());
451         middle += s;
452         }
453
454     if (u->GetProperty().address.ModificationTime() > lastUserUpdateTime)
455         {
456         Encode12str(enc, u->GetProperty().address);
457         strprintf(&s, "<address value=\"%s\" />", enc.c_str());
458         middle += s;
459         }
460
461     if (u->GetProperty().email.ModificationTime() > lastUserUpdateTime)
462         {
463         Encode12str(enc, u->GetProperty().email);
464         strprintf(&s, "<email value=\"%s\" />", enc.c_str());
465         middle += s;
466         }
467
468     std::vector<USER_PROPERTY_LOGGED<std::string> *> userdata;
469     userdata.push_back(u->GetProperty().userdata0.GetPointer());
470     userdata.push_back(u->GetProperty().userdata1.GetPointer());
471     userdata.push_back(u->GetProperty().userdata2.GetPointer());
472     userdata.push_back(u->GetProperty().userdata3.GetPointer());
473     userdata.push_back(u->GetProperty().userdata4.GetPointer());
474     userdata.push_back(u->GetProperty().userdata5.GetPointer());
475     userdata.push_back(u->GetProperty().userdata6.GetPointer());
476     userdata.push_back(u->GetProperty().userdata7.GetPointer());
477     userdata.push_back(u->GetProperty().userdata8.GetPointer());
478     userdata.push_back(u->GetProperty().userdata9.GetPointer());
479
480     std::string tmpI;
481     for (unsigned i = 0; i < userdata.size(); i++)
482         {
483         if (userdata[i]->ModificationTime() > lastUserUpdateTime)
484             {
485             Encode12str(enc, userdata[i]->Get());
486             s = "<UserData" + x2str(i, tmpI) + " value=\"" + enc + "\" />";
487             middle += s;
488             }
489         }
490
491     if (u->GetProperty().realName.ModificationTime() > lastUserUpdateTime)
492         {
493         Encode12str(enc, u->GetProperty().realName);
494         strprintf(&s, "<name value=\"%s\" />", enc.c_str());
495         middle += s;
496         }
497
498     if (u->GetProperty().group.ModificationTime() > lastUserUpdateTime)
499         {
500         Encode12str(enc, u->GetProperty().group);
501         strprintf(&s, "<GROUP value=\"%s\" />", enc.c_str());
502         middle += s;
503         }
504
505     if (u->GetProperty().alwaysOnline.ModificationTime() > lastUserUpdateTime)
506         {
507         strprintf(&s, "<aonline value=\"%d\" />", u->GetProperty().alwaysOnline.Get());
508         middle += s;
509         }
510
511     if (u->GetCurrIPModificationTime() > lastUserUpdateTime)
512         {
513         strprintf(&s, "<currip value=\"%s\" />", inet_ntostring(u->GetCurrIP()).c_str());
514         middle += s;
515         }
516
517
518     if (u->GetConnectedModificationTime() > lastUserUpdateTime)
519         {
520         strprintf(&s, "<status value=\"%d\" />", u->GetConnected());
521         middle += s;
522         }
523
524     if (u->GetPingTime() > lastUserUpdateTime)
525         {
526         strprintf(&s, "<PingTime value=\"%lu\" />", u->GetPingTime());
527         middle += s;
528         }
529
530     if (u->GetProperty().ips.ModificationTime() > lastUserUpdateTime)
531         {
532         std::ostringstream sstr;
533         sstr << u->GetProperty().ips.Get();
534         strprintf(&s, "<ip value=\"%s\" />", sstr.str().c_str());
535         middle += s;
536         }
537
538     char st[50];
539     traffStart = "<traff";
540     DIR_TRAFF upload;
541     DIR_TRAFF download;
542     download = u->GetProperty().down.Get();
543     upload = u->GetProperty().up.Get();
544     traffMiddle = "";
545
546     if (u->GetProperty().up.ModificationTime() > lastUserUpdateTime)
547         {
548         for (int j = 0; j < DIR_NUM; j++)
549             {
550             std::string s;
551             x2str(upload[j], s);
552             sprintf(st, " MU%d=\"%s\" ", j, s.c_str());
553             traffMiddle += st;
554             }
555         }
556
557     if (u->GetProperty().down.ModificationTime() > lastUserUpdateTime)
558         {
559         for (int j = 0; j < DIR_NUM; j++)
560             {
561             x2str(download[j], s);
562             sprintf(st, " MD%d=\"%s\" ", j, s.c_str());
563             traffMiddle += st;
564             }
565         }
566
567     traffFinish = " />";
568     if (traffMiddle.length() > 0)
569         {
570         middle += traffStart;
571         middle += traffMiddle;
572         middle += traffFinish;
573         }
574
575     if (u->GetProperty().disabled.ModificationTime() > lastUserUpdateTime)
576         {
577         strprintf(&s, "<down value=\"%d\" />", u->GetProperty().disabled.Get());
578         middle += s;
579         }
580
581     if (u->GetProperty().disabledDetailStat.ModificationTime() > lastUserUpdateTime)
582         {
583         strprintf(&s, "<DisableDetailStat value=\"%d\" />", u->GetProperty().disabledDetailStat.Get());
584         middle += s;
585         }
586
587     //printfd(__FILE__, ">>>>> %s\n", s.c_str());
588
589     if (u->GetProperty().passive.ModificationTime() > lastUserUpdateTime)
590         {
591         strprintf(&s, "<passive value=\"%d\" />", u->GetProperty().passive.Get());
592         middle += s;
593         }
594
595     if (u->GetProperty().lastCashAdd.ModificationTime() > lastUserUpdateTime)
596         {
597         strprintf(&s, "<LastCash value=\"%f\" />", u->GetProperty().lastCashAdd.Get());
598         middle += s;
599         }
600
601     if (u->GetProperty().lastCashAddTime.ModificationTime() > lastUserUpdateTime)
602         {
603         strprintf(&s, "<LastTimeCash value=\"%ld\" />", u->GetProperty().lastCashAddTime.Get());
604         middle += s;
605         }
606
607
608     if (u->GetProperty().lastActivityTime.ModificationTime() > lastUserUpdateTime)
609         {
610         strprintf(&s, "<LastActivityTime value=\"%ld\" />", u->GetProperty().lastActivityTime.Get());
611         middle += s;
612         }
613
614     if (u->GetProperty().creditExpire.ModificationTime() > lastUserUpdateTime)
615         {
616         strprintf(&s, "<CreditExpire value=\"%ld\" />", u->GetProperty().creditExpire.Get());
617         middle += s;
618         }
619
620
621     userFinish = "</user>";
622
623     if (middle.length() > 0)
624         {
625         /*printfd(__FILE__, "login: %s\n", u->GetLogin().c_str());
626         printfd(__FILE__, "middle: %s\n", middle.c_str());*/
627
628         answerList->push_back(userStart);
629         answerList->push_back(middle);
630         answerList->push_back(userFinish);
631         }
632     }
633
634 users->CloseSearch(h);
635
636 //answerList->push_back("</Users>");
637
638 answerList->push_back("</Users>");
639 }
640 //-----------------------------------------------------------------------------
641 //  ADD USER
642 //-----------------------------------------------------------------------------
643 int PARSER_ADD_USER::ParseStart(void *, const char *el, const char **attr)
644 {
645 depth++;
646
647 if (depth == 1)
648     {
649     if (strcasecmp(el, "AddUser") == 0)
650         {
651         return 0;
652         }
653     }
654 else
655     {
656     if (strcasecmp(el, "login") == 0)
657         {
658         login = attr[1];
659         return 0;
660         }
661     }
662 return -1;
663 }
664 //-----------------------------------------------------------------------------
665 int PARSER_ADD_USER::ParseEnd(void *, const char *el)
666 {
667 if (depth == 1)
668     {
669     if (strcasecmp(el, "AddUser") == 0)
670         {
671         CreateAnswer();
672         depth--;
673         return 0;
674         }
675     }
676
677 depth--;
678 return -1;
679 }
680 //-----------------------------------------------------------------------------
681 void PARSER_ADD_USER::Reset()
682 {
683 BASE_PARSER::Reset();
684 depth = 0;
685 }
686 //-----------------------------------------------------------------------------
687 void PARSER_ADD_USER::CreateAnswer()
688 {
689 //answerList->clear();
690 answerList->erase(answerList->begin(), answerList->end());
691
692 if (CheckUserData() == 0)
693     {
694     answerList->push_back("<AddUser result=\"ok\"/>");
695     }
696 else
697     {
698     answerList->push_back("<AddUser result=\"error\" reason=\"Access denied\"/>");
699     }
700 }
701 //-----------------------------------------------------------------------------
702 int PARSER_ADD_USER::CheckUserData()
703 {
704 USER_PTR u;
705 if (users->FindByName(login, &u))
706     {
707     return users->Add(login, currAdmin);
708     }
709 return -1;
710 }
711 //-----------------------------------------------------------------------------
712 //  PARSER CHG USER
713 //-----------------------------------------------------------------------------
714 PARSER_CHG_USER::PARSER_CHG_USER()
715     : BASE_PARSER(),
716       usr(NULL),
717       ucr(NULL),
718       upr(NULL),
719       downr(NULL),
720       cashMsg(),
721       login(),
722       cashMustBeAdded(false),
723       res(0)
724 {
725 Reset();
726 }
727 //-----------------------------------------------------------------------------
728 PARSER_CHG_USER::~PARSER_CHG_USER()
729 {
730 delete usr;
731 delete ucr;
732 delete[] upr;
733 delete[] downr;
734 }
735 //-----------------------------------------------------------------------------
736 void PARSER_CHG_USER::Reset()
737 {
738 depth = 0;
739 delete usr;
740
741 delete ucr;
742
743 delete[] upr;
744
745 delete[] downr;
746
747 usr = new USER_STAT_RES;
748 ucr = new USER_CONF_RES;
749
750 upr = new RESETABLE<uint64_t>[DIR_NUM];
751 downr = new RESETABLE<uint64_t>[DIR_NUM];
752 }
753 //-----------------------------------------------------------------------------
754 std::string PARSER_CHG_USER::EncChar2String(const char * strEnc)
755 {
756 std::string str;
757 Decode21str(str, strEnc);
758 return str;
759 }
760 //-----------------------------------------------------------------------------
761 int PARSER_CHG_USER::ParseStart(void *, const char *el, const char **attr)
762 {
763 depth++;
764
765 if (depth == 1)
766     {
767     if (strcasecmp(el, "SetUser") == 0)
768         {
769         return 0;
770         }
771     }
772 else
773     {
774     //printfd(__FILE__, "el=%s\n", el);
775     if (strcasecmp(el, "login") == 0)
776         {
777         login = attr[1];
778         return 0;
779         }
780
781     if (strcasecmp(el, "ip") == 0)
782         {
783         try
784             {
785             ucr->ips = StrToIPS(attr[1]);
786             }
787         catch (...)
788             {
789             printfd(__FILE__, "StrToIPS Error!\n");
790             }
791         }
792
793     if (strcasecmp(el, "password") == 0)
794         {
795         ucr->password = attr[1];
796         return 0;
797         }
798
799     if (strcasecmp(el, "address") == 0)
800         {
801         ucr->address = EncChar2String(attr[1]);
802         return 0;
803         }
804
805     if (strcasecmp(el, "aonline") == 0)
806         {
807         ucr->alwaysOnline = (*(attr[1]) != '0');
808         return 0;
809         }
810
811     if (strcasecmp(el, "cash") == 0)
812         {
813         if (attr[2] && (strcasecmp(attr[2], "msg") == 0))
814             {
815             cashMsg = EncChar2String(attr[3]);
816             }
817
818         double cash;
819         if (strtodouble2(attr[1], cash) == 0)
820             usr->cash = cash;
821
822         if (strcasecmp(attr[0], "set") == 0)
823             cashMustBeAdded = false;
824
825         if (strcasecmp(attr[0], "add") == 0)
826             cashMustBeAdded = true;
827
828         return 0;
829         }
830
831     if (strcasecmp(el, "CreditExpire") == 0)
832         {
833         long int creditExpire = 0;
834         if (str2x(attr[1], creditExpire) == 0)
835             ucr->creditExpire = (time_t)creditExpire;
836
837         return 0;
838         }
839
840     if (strcasecmp(el, "credit") == 0)
841         {
842         double credit;
843         if (strtodouble2(attr[1], credit) == 0)
844             ucr->credit = credit;
845         return 0;
846         }
847
848     if (strcasecmp(el, "freemb") == 0)
849         {
850         double freeMb;
851         if (strtodouble2(attr[1], freeMb) == 0)
852             usr->freeMb = freeMb;
853         return 0;
854         }
855
856     if (strcasecmp(el, "down") == 0)
857         {
858         int down = 0;
859         if (str2x(attr[1], down) == 0)
860             ucr->disabled = down;
861         return 0;
862         }
863
864     if (strcasecmp(el, "DisableDetailStat") == 0)
865         {
866         int disabledDetailStat = 0;
867         if (str2x(attr[1], disabledDetailStat) == 0)
868             ucr->disabledDetailStat = disabledDetailStat;
869         return 0;
870         }
871
872     if (strcasecmp(el, "email") == 0)
873         {
874         ucr->email = EncChar2String(attr[1]);
875         return 0;
876         }
877
878     for (int i = 0; i < USERDATA_NUM; i++)
879         {
880         char name[15];
881         sprintf(name, "userdata%d", i);
882         if (strcasecmp(el, name) == 0)
883             {
884             ucr->userdata[i] = EncChar2String(attr[1]);
885             return 0;
886             }
887         }
888
889     if (strcasecmp(el, "group") == 0)
890         {
891         ucr->group = EncChar2String(attr[1]);
892         return 0;
893         }
894
895     if (strcasecmp(el, "note") == 0)
896         {
897         ucr->note = EncChar2String(attr[1]);
898         return 0;
899         }
900
901     if (strcasecmp(el, "passive") == 0)
902         {
903         int passive = 0;
904         if (str2x(attr[1], passive) == 0)
905             ucr->passive = passive;
906         return 0;
907         }
908
909     if (strcasecmp(el, "phone") == 0)
910         {
911         ucr->phone = EncChar2String(attr[1]);
912         return 0;
913         }
914
915     if (strcasecmp(el, "Name") == 0)
916         {
917         ucr->realName = EncChar2String(attr[1]);
918         return 0;
919         }
920
921     if (strcasecmp(el, "traff") == 0)
922         {
923         int j = 0;
924         int dir;
925         DIR_TRAFF dtu;
926         DIR_TRAFF dtd;
927         uint64_t t = 0;
928         while (attr[j])
929             {
930             dir = attr[j][2] - '0';
931
932             if (strncasecmp(attr[j], "md", 2) == 0)
933                 {
934                 str2x(attr[j+1], t);
935                 dtd[dir] = t;
936                 downr[dir] = t;
937                 }
938             if (strncasecmp(attr[j], "mu", 2) == 0)
939                 {
940                 str2x(attr[j+1], t);
941                 dtu[dir] = t;
942                 upr[dir] = t;
943                 }
944             j+=2;
945             }
946         usr->down = dtd;
947         usr->up = dtu;
948         return 0;
949         }
950
951     if (strcasecmp(el, "tariff") == 0)
952         {
953         if (strcasecmp(attr[0], "now") == 0)
954             ucr->tariffName = attr[1];
955
956         if (strcasecmp(attr[0], "delayed") == 0)
957             ucr->nextTariff = attr[1];
958
959         return 0;
960         }
961     }
962 return -1;
963 }
964 //-----------------------------------------------------------------------------
965 int PARSER_CHG_USER::ParseEnd(void *, const char *el)
966 {
967 if (depth == 1)
968     {
969     if (strcasecmp(el, "SetUser") == 0)
970         {
971         AplayChanges();
972         CreateAnswer();
973         depth--;
974         return 0;
975         }
976     }
977
978 depth--;
979 return -1;
980 }
981 //-----------------------------------------------------------------------------
982 void PARSER_CHG_USER::CreateAnswer()
983 {
984 //answerList->clear();
985 answerList->erase(answerList->begin(), answerList->end());
986
987 switch (res)
988     {
989     case 0:
990         answerList->push_back("<SetUser result=\"ok\"/>");
991         break;
992     case -1:
993         answerList->push_back("<SetUser result=\"error\"/>");
994         break;
995     case -2:
996         answerList->push_back("<SetUser result=\"error\"/>");
997         break;
998     default:
999         answerList->push_back("<SetUser result=\"error\"/>");
1000         break;
1001     }
1002
1003 }
1004 //-----------------------------------------------------------------------------
1005 int PARSER_CHG_USER::AplayChanges()
1006 {
1007 printfd(__FILE__, "PARSER_CHG_USER::AplayChanges()\n");
1008 USER_PTR u;
1009
1010 res = 0;
1011 if (users->FindByName(login, &u))
1012     {
1013     res = -1;
1014     return -1;
1015     }
1016
1017 bool check = false;
1018 bool alwaysOnline = u->GetProperty().alwaysOnline;
1019 if (!ucr->alwaysOnline.res_empty())
1020     {
1021     check = true;
1022     alwaysOnline = ucr->alwaysOnline.const_data();
1023     }
1024 bool onlyOneIP = u->GetProperty().ips.ConstData().OnlyOneIP();
1025 if (!ucr->ips.res_empty())
1026     {
1027     check = true;
1028     onlyOneIP = ucr->ips.const_data().OnlyOneIP();
1029     }
1030
1031 if (check && alwaysOnline && !onlyOneIP)
1032     {
1033     printfd(__FILE__, "Requested change leads to a forbidden state: AlwaysOnline with multiple IP's\n");
1034     GetStgLogger()("%s Requested change leads to a forbidden state: AlwaysOnline with multiple IP's", currAdmin->GetLogStr().c_str());
1035     res = -1;
1036     return -1;
1037     }
1038
1039 for (size_t i = 0; i < ucr->ips.const_data().Count(); ++i)
1040     {
1041     CONST_USER_PTR user;
1042     uint32_t ip = ucr->ips.const_data().operator[](i).ip;
1043     if (users->IsIPInUse(ip, login, &user))
1044         {
1045         printfd(__FILE__, "Trying to assign an IP %s to '%s' that is already in use by '%s'\n", inet_ntostring(ip).c_str(), login.c_str(), user->GetLogin().c_str());
1046         GetStgLogger()("%s trying to assign an IP %s to '%s' that is currently in use by '%s'", currAdmin->GetLogStr().c_str(), inet_ntostring(ip).c_str(), login.c_str(), user->GetLogin().c_str());
1047         res = -1;
1048         return -1;
1049         }
1050     }
1051
1052 if (!ucr->ips.res_empty())
1053     if (!u->GetProperty().ips.Set(ucr->ips.const_data(), currAdmin, login, store))
1054         res = -1;
1055
1056 if (!ucr->alwaysOnline.res_empty())
1057     if (!u->GetProperty().alwaysOnline.Set(ucr->alwaysOnline.const_data(),
1058                                       currAdmin, login, store))
1059         res = -1;
1060
1061 if (!ucr->address.res_empty())
1062     if (!u->GetProperty().address.Set(ucr->address.const_data(), currAdmin, login, store))
1063         res = -1;
1064
1065 if (!ucr->creditExpire.res_empty())
1066     if (!u->GetProperty().creditExpire.Set(ucr->creditExpire.const_data(),
1067                                       currAdmin, login, store))
1068         res = -1;
1069
1070 if (!ucr->credit.res_empty())
1071     if (!u->GetProperty().credit.Set(ucr->credit.const_data(), currAdmin, login, store))
1072         res = -1;
1073
1074 if (!usr->freeMb.res_empty())
1075     if (!u->GetProperty().freeMb.Set(usr->freeMb.const_data(), currAdmin, login, store))
1076         res = -1;
1077
1078 if (!ucr->disabled.res_empty())
1079     if (!u->GetProperty().disabled.Set(ucr->disabled.const_data(), currAdmin, login, store))
1080         res = -1;
1081
1082 if (!ucr->disabledDetailStat.res_empty())
1083     if (!u->GetProperty().disabledDetailStat.Set(ucr->disabledDetailStat.const_data(), currAdmin, login, store))
1084         res = -1;
1085
1086 if (!ucr->email.res_empty())
1087     if (!u->GetProperty().email.Set(ucr->email.const_data(), currAdmin, login, store))
1088         res = -1;
1089
1090 if (!ucr->group.res_empty())
1091     if (!u->GetProperty().group.Set(ucr->group.const_data(), currAdmin, login, store))
1092         res = -1;
1093
1094 if (!ucr->note.res_empty())
1095     if (!u->GetProperty().note.Set(ucr->note.const_data(), currAdmin, login, store))
1096         res = -1;
1097
1098 std::vector<USER_PROPERTY_LOGGED<std::string> *> userdata;
1099 userdata.push_back(u->GetProperty().userdata0.GetPointer());
1100 userdata.push_back(u->GetProperty().userdata1.GetPointer());
1101 userdata.push_back(u->GetProperty().userdata2.GetPointer());
1102 userdata.push_back(u->GetProperty().userdata3.GetPointer());
1103 userdata.push_back(u->GetProperty().userdata4.GetPointer());
1104 userdata.push_back(u->GetProperty().userdata5.GetPointer());
1105 userdata.push_back(u->GetProperty().userdata6.GetPointer());
1106 userdata.push_back(u->GetProperty().userdata7.GetPointer());
1107 userdata.push_back(u->GetProperty().userdata8.GetPointer());
1108 userdata.push_back(u->GetProperty().userdata9.GetPointer());
1109
1110 for (int i = 0; i < (int)userdata.size(); i++)
1111     {
1112     if (!ucr->userdata[i].res_empty())
1113         {
1114         if(!userdata[i]->Set(ucr->userdata[i].const_data(), currAdmin, login, store))
1115             res = -1;
1116         }
1117     }
1118
1119 if (!ucr->passive.res_empty())
1120     if (!u->GetProperty().passive.Set(ucr->passive.const_data(), currAdmin, login, store))
1121         res = -1;
1122
1123 if (!ucr->password.res_empty())
1124     if (!u->GetProperty().password.Set(ucr->password.const_data(), currAdmin, login, store))
1125         res = -1;
1126
1127 if (!ucr->phone.res_empty())
1128     if (!u->GetProperty().phone.Set(ucr->phone.const_data(), currAdmin, login, store))
1129         res = -1;
1130
1131 if (!ucr->realName.res_empty())
1132     if (!u->GetProperty().realName.Set(ucr->realName.const_data(), currAdmin, login, store))
1133         res = -1;
1134
1135
1136 if (!usr->cash.res_empty())
1137     {
1138     //if (*currAdmin->GetPriv()->userCash)
1139         {
1140         if (cashMustBeAdded)
1141             {
1142             if (!u->GetProperty().cash.Set(usr->cash.const_data() + u->GetProperty().cash,
1143                                            currAdmin,
1144                                            login,
1145                                            store,
1146                                            cashMsg))
1147                 res = -1;
1148             }
1149         else
1150             {
1151             if (!u->GetProperty().cash.Set(usr->cash.const_data(), currAdmin, login, store, cashMsg))
1152                 res = -1;
1153             }
1154         }
1155     }
1156
1157
1158 if (!ucr->tariffName.res_empty())
1159     {
1160     if (tariffs->FindByName(ucr->tariffName.const_data()))
1161         {
1162         if (!u->GetProperty().tariffName.Set(ucr->tariffName.const_data(), currAdmin, login, store))
1163             res = -1;
1164         u->ResetNextTariff();
1165         }
1166     else
1167         {
1168         //WriteServLog("SetUser: Tariff %s not found", ud.conf.tariffName.c_str());
1169         res = -1;
1170         }
1171     }
1172
1173 if (!ucr->nextTariff.res_empty())
1174     {
1175     if (tariffs->FindByName(ucr->nextTariff.const_data()))
1176         {
1177         if (!u->GetProperty().nextTariff.Set(ucr->nextTariff.const_data(), currAdmin, login, store))
1178             res = -1;
1179         }
1180     else
1181         {
1182         //WriteServLog("SetUser: Tariff %s not found", ud.conf.tariffName.c_str());
1183         res = -1;
1184         }
1185     }
1186
1187 DIR_TRAFF up = u->GetProperty().up;
1188 DIR_TRAFF down = u->GetProperty().down;
1189 int upCount = 0;
1190 int downCount = 0;
1191 for (int i = 0; i < DIR_NUM; i++)
1192     {
1193     if (!upr[i].res_empty())
1194         {
1195         up[i] = upr[i];
1196         upCount++;
1197         }
1198     if (!downr[i].res_empty())
1199         {
1200         down[i] = downr[i];
1201         downCount++;
1202         }
1203     }
1204
1205 if (upCount)
1206     if (!u->GetProperty().up.Set(up, currAdmin, login, store))
1207         res = -1;
1208
1209 if (downCount)
1210     if (!u->GetProperty().down.Set(down, currAdmin, login, store))
1211         res = -1;
1212
1213 /*if (!usr->down.res_empty())
1214     {
1215     u->GetProperty().down.Set(usr->down.const_data(), currAdmin, login, store);
1216     }
1217 if (!usr->up.res_empty())
1218     {
1219     u->GetProperty().up.Set(usr->up.const_data(), currAdmin, login, store);
1220     }*/
1221
1222 u->WriteConf();
1223 u->WriteStat();
1224
1225 return 0;
1226 }
1227 //-----------------------------------------------------------------------------
1228 //      SEND MESSAGE
1229 //-----------------------------------------------------------------------------
1230 int PARSER_SEND_MESSAGE::ParseStart(void *, const char *el, const char **attr)
1231 {
1232 if (strcasecmp(el, "Message") == 0)
1233     {
1234     for (int i = 0; i < 14; i++)
1235         {
1236         if (attr[i] == NULL)
1237             {
1238             result = res_params_error;
1239             CreateAnswer();
1240             printfd(__FILE__, "To few parameters\n");
1241             return 0;
1242             }
1243         }
1244
1245     for (int i = 0; i < 14; i+=2)
1246         {
1247         if (strcasecmp(attr[i], "login") == 0)
1248             {
1249             ParseLogins(attr[i+1]);
1250             /*if (users->FindByName(login, &u))
1251                 {
1252                 result = res_unknown;
1253                 break;
1254                 }*/
1255             }
1256
1257         if (strcasecmp(attr[i], "MsgVer") == 0)
1258             {
1259             str2x(attr[i+1], msg.header.ver);
1260             if (msg.header.ver != 1)
1261                 result = res_params_error;
1262             }
1263
1264         if (strcasecmp(attr[i], "MsgType") == 0)
1265             {
1266             str2x(attr[i+1], msg.header.type);
1267             if (msg.header.type != 1)
1268                 result = res_params_error;
1269             }
1270
1271         if (strcasecmp(attr[i], "Repeat") == 0)
1272             {
1273             str2x(attr[i+1], msg.header.repeat);
1274             if (msg.header.repeat < 0)
1275                 result = res_params_error;
1276             }
1277
1278         if (strcasecmp(attr[i], "RepeatPeriod") == 0)
1279             {
1280             str2x(attr[i+1], msg.header.repeatPeriod);
1281             }
1282
1283         if (strcasecmp(attr[i], "ShowTime") == 0)
1284             {
1285             str2x(attr[i+1], msg.header.showTime);
1286             }
1287
1288         if (strcasecmp(attr[i], "Text") == 0)
1289             {
1290             Decode21str(msg.text, attr[i+1]);
1291             result = res_ok;
1292             }
1293         }
1294     return 0;
1295     }
1296 return -1;
1297 }
1298 //-----------------------------------------------------------------------------
1299 int PARSER_SEND_MESSAGE::ParseEnd(void *, const char *el)
1300 {
1301 //MSG msg;
1302 if (strcasecmp(el, "Message") == 0)
1303     {
1304     result = res_unknown;
1305     for (unsigned i = 0; i < logins.size(); i++)
1306         {
1307         if (users->FindByName(logins[i], &u))
1308             {
1309             printfd(__FILE__, "User not found. %s\n", logins[i].c_str());
1310             continue;
1311             }
1312         msg.header.creationTime = static_cast<unsigned int>(stgTime);
1313         u->AddMessage(&msg);
1314         result = res_ok;
1315         }
1316     /*if (result == res_ok)
1317         {
1318         if (strcmp(login, "*") == 0)
1319             {
1320             msg.text = text;
1321             msg.prio = pri;
1322             printfd(__FILE__, "SendMsg text: %s\n", text);
1323             users->GetAllUsers(SendMessageAllUsers, &msg);
1324             }
1325         else
1326             {
1327             u->AddMessage(pri, text);
1328             }
1329         }*/
1330     CreateAnswer();
1331     return 0;
1332     }
1333 return -1;
1334 }
1335 //-----------------------------------------------------------------------------
1336 int PARSER_SEND_MESSAGE::ParseLogins(const char * login)
1337 {
1338 char * p;
1339 char * l = new char[strlen(login) + 1];
1340 strcpy(l, login);
1341 p = strtok(l, ":");
1342 logins.clear();
1343 while(p)
1344     {
1345     logins.push_back(p);
1346     p = strtok(NULL, ":");
1347     }
1348
1349 delete[] l;
1350 return 0;
1351 }
1352 //-----------------------------------------------------------------------------
1353 void PARSER_SEND_MESSAGE::CreateAnswer()
1354 {
1355 //answerList->clear();
1356 answerList->erase(answerList->begin(), answerList->end());
1357 //answerList->push_back("<SendMessageResult value=\"ok\"/>");
1358 //
1359 switch (result)
1360     {
1361     case res_ok:
1362         answerList->push_back("<SendMessageResult value=\"ok\"/>");
1363         break;
1364     case res_params_error:
1365         printfd(__FILE__, "res_params_error\n");
1366         answerList->push_back("<SendMessageResult value=\"Parameters error\"/>");
1367         break;
1368     case res_unknown:
1369         printfd(__FILE__, "res_unknown\n");
1370         answerList->push_back("<SendMessageResult value=\"Unknown user\"/>");
1371         break;
1372     default:
1373         printfd(__FILE__, "res_default\n");
1374     }
1375
1376 }
1377 //-----------------------------------------------------------------------------
1378 //      DEL USER
1379 //-----------------------------------------------------------------------------
1380 int PARSER_DEL_USER::ParseStart(void *, const char *el, const char **attr)
1381 {
1382 res = 0;
1383 if (strcasecmp(el, "DelUser") == 0)
1384     {
1385     if (attr[0] == NULL || attr[1] == NULL)
1386         {
1387         //CreateAnswer("Parameters error!");
1388         CreateAnswer();
1389         return 0;
1390         }
1391
1392     if (users->FindByName(attr[1], &u))
1393         {
1394         res = 1;
1395         CreateAnswer();
1396         return 0;
1397         }
1398     CreateAnswer();
1399     return 0;
1400     }
1401 return -1;
1402 }
1403 //-----------------------------------------------------------------------------
1404 int PARSER_DEL_USER::ParseEnd(void *, const char *el)
1405 {
1406 if (strcasecmp(el, "DelUser") == 0)
1407     {
1408     if (!res)
1409         users->Del(u->GetLogin(), currAdmin);
1410
1411     return 0;
1412     }
1413 return -1;
1414 }
1415 //-----------------------------------------------------------------------------
1416 void PARSER_DEL_USER::CreateAnswer()
1417 {
1418 if (res)
1419     answerList->push_back("<DelUser value=\"error\" reason=\"User not found\"/>");
1420 else
1421     answerList->push_back("<DelUser value=\"ok\"/>");
1422 }
1423 //-----------------------------------------------------------------------------
1424 /*void PARSERDELUSER::CreateAnswer(char * mes)
1425 {
1426 //answerList->clear();
1427 answerList->erase(answerList->begin(), answerList->end());
1428
1429 char str[255];
1430 sprintf(str, "<DelUser value=\"%s\"/>", mes);
1431 answerList->push_back(str);
1432 }*/
1433 //-----------------------------------------------------------------------------
1434 //  CHECK USER
1435 // <checkuser login="vasya" password=\"123456\"/>
1436 //-----------------------------------------------------------------------------
1437 int PARSER_CHECK_USER::ParseStart(void *, const char *el, const char **attr)
1438 {
1439 result = false;
1440
1441 if (strcasecmp(el, "CheckUser") == 0)
1442     {
1443     if (attr[0] == NULL || attr[1] == NULL
1444      || attr[2] == NULL || attr[3] == NULL)
1445         {
1446         result = false;
1447         CreateAnswer();
1448         printfd(__FILE__, "PARSER_CHECK_USER - attr err\n");
1449         return 0;
1450         }
1451
1452     USER_PTR user;
1453     if (users->FindByName(attr[1], &user))
1454         {
1455         result = false;
1456         CreateAnswer();
1457         printfd(__FILE__, "PARSER_CHECK_USER - login err\n");
1458         return 0;
1459         }
1460
1461     if (strcmp(user->GetProperty().password.Get().c_str(), attr[3]))
1462         {
1463         result = false;
1464         CreateAnswer();
1465         printfd(__FILE__, "PARSER_CHECK_USER - passwd err\n");
1466         return 0;
1467         }
1468
1469     result = true;
1470     CreateAnswer();
1471     return 0;
1472     }
1473 return -1;
1474 }
1475 //-----------------------------------------------------------------------------
1476 int PARSER_CHECK_USER::ParseEnd(void *, const char *el)
1477 {
1478 if (strcasecmp(el, "CheckUser") == 0)
1479     {
1480     return 0;
1481     }
1482 return -1;
1483 }
1484 //-----------------------------------------------------------------------------
1485 void PARSER_CHECK_USER::CreateAnswer()
1486 {
1487 if (result)
1488     answerList->push_back("<CheckUser value=\"Ok\"/>");
1489 else
1490     answerList->push_back("<CheckUser value=\"Err\"/>");
1491 }
1492 //-----------------------------------------------------------------------------
1493 //-----------------------------------------------------------------------------
1494 //-----------------------------------------------------------------------------