]> git.stg.codes - stg.git/blob - projects/sgconf/main.cpp
c4ca29cbb5a90eb83b498df6f2b10407d5ed82d4
[stg.git] / projects / sgconf / main.cpp
1 /*
2  *    This program is free software; you can redistribute it and/or modify
3  *    it under the terms of the GNU General Public License as published by
4  *    the Free Software Foundation; either version 2 of the License, or
5  *    (at your option) any later version.
6  *
7  *    This program is distributed in the hope that it will be useful,
8  *    but WITHOUT ANY WARRANTY; without even the implied warranty of
9  *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  *    GNU General Public License for more details.
11  *
12  *    You should have received a copy of the GNU General Public License
13  *    along with this program; if not, write to the Free Software
14  *    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
15  */
16
17 /*
18  *    Author : Boris Mikhailenko <stg34@stargazer.dp.ua>
19  */
20
21  /*
22  $Author: faust $
23  $Revision: 1.25 $
24  $Date: 2010/03/25 14:37:43 $
25  */
26
27 #include "request.h"
28 #include "common_sg.h"
29 #include "sg_error_codes.h"
30
31 #include "stg/user_conf.h"
32 #include "stg/user_stat.h"
33 #include "stg/common.h"
34
35 #include <cerrno>
36 #include <clocale>
37 #include <cstdio>
38 #include <cstdlib>
39 #include <cstring>
40 #include <string>
41 #include <sstream>
42
43 #include <unistd.h>
44 #include <getopt.h>
45 #include <iconv.h>
46 #include <langinfo.h>
47
48 namespace
49 {
50
51 template <typename T>
52 struct ARRAY_TYPE
53 {
54 typedef typename T::value_type type;
55 };
56
57 template <typename T>
58 struct ARRAY_TYPE<T[]>
59 {
60 typedef T type;
61 };
62
63 template <typename T, size_t N>
64 struct ARRAY_TYPE<T[N]>
65 {
66 typedef T type;
67 };
68
69 template <typename T>
70 bool SetArrayItem(T & array, const char * index, const typename ARRAY_TYPE<T>::type & value)
71 {
72 size_t pos = 0;
73 if (str2x(index, pos))
74     return false;
75 array[pos] = value;
76 return true;
77 }
78
79 void Usage(bool full);
80 void UsageConnection();
81 void UsageAdmins(bool full);
82 void UsageTariffs(bool full);
83 void UsageUsers(bool full);
84 void UsageServices(bool full);
85 void UsageCorporations(bool full);
86
87 } // namespace anonymous
88
89 time_t stgTime;
90
91 struct option long_options_get[] = {
92 {"server",      1, 0, 's'},  //Server
93 {"port",        1, 0, 'p'},  //Port
94 {"admin",       1, 0, 'a'},  //Admin
95 {"admin_pass",  1, 0, 'w'},  //passWord
96 {"user",        1, 0, 'u'},  //User
97 {"addcash",     0, 0, 'c'},  //Add Cash
98 //{"setcash",     0, 0, 'v'},  //Set Cash
99 {"credit",      0, 0, 'r'},  //cRedit
100 {"tariff",      0, 0, 't'},  //Tariff
101 {"message",     0, 0, 'm'},  //message
102 {"password",    0, 0, 'o'},  //password
103 {"down",        0, 0, 'd'},  //down
104 {"passive",     0, 0, 'i'},  //passive
105 {"disable-stat",0, 0, 'S'},  //disable detail stat
106 {"always-online",0, 0, 'O'}, //always online
107 {"session-upload",   1, 0, 500},  //SU0
108 {"session-download", 1, 0, 501},  //SD0
109 {"month-upload",     1, 0, 502},  //MU0
110 {"month-download",   1, 0, 503},  //MD0
111
112 {"user-data",   1, 0, 700},  //UserData0
113
114 {"prepaid",     0, 0, 'e'},  //prepaid traff
115 {"create",      0, 0, 'n'},  //create
116 {"delete",      0, 0, 'l'},  //delete
117
118 {"note",        0, 0, 'N'},  //Note
119 {"name",        0, 0, 'A'},  //nAme
120 {"address",     0, 0, 'D'},  //aDdress
121 {"email",       0, 0, 'L'},  //emaiL
122 {"phone",       0, 0, 'P'},  //phone
123 {"group",       0, 0, 'G'},  //Group
124 {"ip",          0, 0, 'I'},  //IP-address of user
125 {"authorized-by",0, 0, 800}, //always online
126
127 {0, 0, 0, 0}};
128
129 struct option long_options_set[] = {
130 {"server",      1, 0, 's'},  //Server
131 {"port",        1, 0, 'p'},  //Port
132 {"admin",       1, 0, 'a'},  //Admin
133 {"admin_pass",  1, 0, 'w'},  //passWord
134 {"user",        1, 0, 'u'},  //User
135 {"addcash",     1, 0, 'c'},  //Add Cash
136 {"setcash",     1, 0, 'v'},  //Set Cash
137 {"credit",      1, 0, 'r'},  //cRedit
138 {"tariff",      1, 0, 't'},  //Tariff
139 {"message",     1, 0, 'm'},  //message
140 {"password",    1, 0, 'o'},  //password
141 {"down",        1, 0, 'd'},  //down
142 {"passive",     1, 0, 'i'},  //passive
143 {"disable-stat",1, 0, 'S'},  //disable detail stat
144 {"always-online",1, 0, 'O'},  //always online
145 {"session-upload",   1, 0, 500},  //U0
146 {"session-download", 1, 0, 501},  //U1
147 {"month-upload",     1, 0, 502},  //U2
148 {"month-download",   1, 0, 503},  //U3
149
150 {"user-data",        1, 0, 700},  //UserData
151
152 {"prepaid",     1, 0, 'e'},  //prepaid traff
153 {"create",      1, 0, 'n'},  //create
154 {"delete",      1, 0, 'l'},  //delete
155
156 {"note",        1, 0, 'N'},  //Note
157 {"name",        1, 0, 'A'},  //nAme
158 {"address",     1, 0, 'D'},  //aDdress
159 {"email",       1, 0, 'L'},  //emaiL
160 {"phone",       1, 0, 'P'},  //phone
161 {"group",       1, 0, 'G'},  //Group
162 {"ip",          0, 0, 'I'},  //IP-address of user
163
164 {0, 0, 0, 0}};
165
166 //-----------------------------------------------------------------------------
167 CASH_INFO ParseCash(const char * str)
168 {
169 //-c 123.45:log message
170 std::string cashString;
171 std::string message;
172 const char * pos = strchr(str, ':');
173 if (pos != NULL)
174     {
175     cashString.append(str, pos);
176     message.append(pos + 1);
177     }
178 else
179     cashString = str;
180
181 double cash = 0;
182 if (strtodouble2(cashString, cash) != 0)
183     {
184     printf("Incorrect cash value %s\n", str);
185     exit(PARAMETER_PARSING_ERR_CODE);
186     }
187
188 return CASH_INFO(cash, message);
189 }
190 //-----------------------------------------------------------------------------
191 double ParseCredit(const char * c)
192 {
193 double credit;
194 if (strtodouble2(c, credit) != 0)
195     {
196     printf("Incorrect credit value %s\n", c);
197     exit(PARAMETER_PARSING_ERR_CODE);
198     }
199
200 return credit;
201 }
202 //-----------------------------------------------------------------------------
203 double ParsePrepaidTraffic(const char * c)
204 {
205 double credit;
206 if (strtodouble2(c, credit) != 0)
207     {
208     printf("Incorrect prepaid traffic value %s\n", c);
209     exit(PARAMETER_PARSING_ERR_CODE);
210     }
211
212 return credit;
213 }
214 //-----------------------------------------------------------------------------
215 int64_t ParseTraff(const char * c)
216 {
217 int64_t traff;
218 if (str2x(c, traff) != 0)
219     {
220     printf("Incorrect credit value %s\n", c);
221     exit(PARAMETER_PARSING_ERR_CODE);
222     }
223
224 return traff;
225 }
226 //-----------------------------------------------------------------------------
227 bool ParseDownPassive(const char * dp)
228 {
229 if (!(dp[1] == 0 && (dp[0] == '1' || dp[0] == '0')))
230     {
231     printf("Incorrect value %s\n", dp);
232     exit(PARAMETER_PARSING_ERR_CODE);
233     }
234
235 return dp[0] - '0';
236 }
237 //-----------------------------------------------------------------------------
238 void ParseTariff(const char * str, RESETABLE<std::string> & tariffName, RESETABLE<std::string> & nextTariff)
239 {
240 const char * pos = strchr(str, ':');
241 if (pos != NULL)
242     {
243     std::string tariff(str, pos);
244     if (strcmp(pos + 1, "now") == 0)
245         tariffName = tariff;
246     else if (strcmp(pos + 1, "delayed") == 0)
247         nextTariff = tariff;
248     else
249         {
250         printf("Incorrect tariff value '%s'. Should be '<tariff>', '<tariff>:now' or '<tariff>:delayed'.\n", str);
251         exit(PARAMETER_PARSING_ERR_CODE);
252         }
253     }
254 else
255     tariffName = str;
256 }
257 //-----------------------------------------------------------------------------
258 time_t ParseCreditExpire(const char * str)
259 {
260 struct tm brokenTime;
261
262 brokenTime.tm_wday = 0;
263 brokenTime.tm_yday = 0;
264 brokenTime.tm_isdst = 0;
265 brokenTime.tm_hour = 0;
266 brokenTime.tm_min = 0;
267 brokenTime.tm_sec = 0;
268
269 stg_strptime(str, "%Y-%m-%d", &brokenTime);
270
271 return stg_timegm(&brokenTime);
272 }
273 //-----------------------------------------------------------------------------
274 void ParseAnyString(const char * c, string * msg, const char * enc)
275 {
276 iconv_t cd;
277 char * ob = new char[strlen(c) + 1];
278 char * ib = new char[strlen(c) + 1];
279
280 strcpy(ib, c);
281
282 char * outbuf = ob;
283 char * inbuf = ib;
284
285 setlocale(LC_ALL, "");
286
287 char charsetF[255];
288 strncpy(charsetF, nl_langinfo(CODESET), 255);
289
290 const char * charsetT = enc;
291
292 size_t nconv = 1;
293
294 size_t insize = strlen(ib);
295 size_t outsize = strlen(ib);
296
297 insize = strlen(c);
298
299 cd = iconv_open(charsetT, charsetF);
300 if (cd == (iconv_t) -1)
301     {
302     if (errno == EINVAL)
303         {
304         printf("Warning: iconv from %s to %s failed\n", charsetF, charsetT);
305         *msg = c;
306         return;
307         }
308     else
309         printf("error iconv_open\n");
310
311     exit(ICONV_ERR_CODE);
312     }
313
314 #if defined(FREE_BSD) || defined(FREE_BSD5)
315 nconv = iconv (cd, (const char**)&inbuf, &insize, &outbuf, &outsize);
316 #else
317 nconv = iconv (cd, &inbuf, &insize, &outbuf, &outsize);
318 #endif
319 //printf("nconv=%d outsize=%d\n", nconv, outsize);
320 if (nconv == (size_t) -1)
321     {
322     if (errno != EINVAL)
323         {
324         printf("iconv error\n");
325         exit(ICONV_ERR_CODE);
326         }
327     }
328
329 *outbuf = L'\0';
330
331 iconv_close(cd);
332 *msg = ob;
333
334 delete[] ob;
335 delete[] ib;
336 }
337 //-----------------------------------------------------------------------------
338 void CreateRequestSet(REQUEST * req, char * r)
339 {
340 const int strLen = 10024;
341 char str[strLen];
342 memset(str, 0, strLen);
343
344 r[0] = 0;
345
346 if (!req->usrMsg.empty())
347     {
348     string msg;
349     Encode12str(msg, req->usrMsg.data());
350     sprintf(str, "<Message login=\"%s\" msgver=\"1\" msgtype=\"1\" repeat=\"0\" repeatperiod=\"0\" showtime=\"0\" text=\"%s\"/>", req->login.const_data().c_str(), msg.c_str());
351     //sprintf(str, "<message login=\"%s\" priority=\"0\" text=\"%s\"/>\n", req->login, msg);
352     strcat(r, str);
353     return;
354     }
355
356 if (req->deleteUser)
357     {
358     sprintf(str, "<DelUser login=\"%s\"/>", req->login.const_data().c_str());
359     strcat(r, str);
360     //printf("%s\n", r);
361     return;
362     }
363
364 if (req->createUser)
365     {
366     sprintf(str, "<AddUser> <login value=\"%s\"/> </AddUser>", req->login.const_data().c_str());
367     strcat(r, str);
368     //printf("%s\n", r);
369     return;
370     }
371
372 strcat(r, "<SetUser>\n");
373 sprintf(str, "<login value=\"%s\"/>\n", req->login.const_data().c_str());
374 strcat(r, str);
375 if (!req->credit.empty())
376     {
377     sprintf(str, "<credit value=\"%f\"/>\n", req->credit.const_data());
378     strcat(r, str);
379     }
380
381 if (!req->creditExpire.empty())
382     {
383     sprintf(str, "<creditExpire value=\"%ld\"/>\n", req->creditExpire.const_data());
384     strcat(r, str);
385     }
386
387 if (!req->prepaidTraff.empty())
388     {
389     sprintf(str, "<FreeMb value=\"%f\"/>\n", req->prepaidTraff.const_data());
390     strcat(r, str);
391     }
392
393 if (!req->cash.empty())
394     {
395     string msg;
396     Encode12str(msg, req->message);
397     sprintf(str, "<cash add=\"%f\" msg=\"%s\"/>\n", req->cash.const_data(), msg.c_str());
398     strcat(r, str);
399     }
400
401 if (!req->setCash.empty())
402     {
403     string msg;
404     Encode12str(msg, req->message);
405     sprintf(str, "<cash set=\"%f\" msg=\"%s\"/>\n", req->setCash.const_data(), msg.c_str());
406     strcat(r, str);
407     }
408
409 if (!req->usrPasswd.empty())
410     {
411     sprintf(str, "<password value=\"%s\" />\n", req->usrPasswd.const_data().c_str());
412     strcat(r, str);
413     }
414
415 if (!req->down.empty())
416     {
417     sprintf(str, "<down value=\"%d\" />\n", req->down.const_data());
418     strcat(r, str);
419     }
420
421 if (!req->passive.empty())
422     {
423     sprintf(str, "<passive value=\"%d\" />\n", req->passive.const_data());
424     strcat(r, str);
425     }
426
427 if (!req->disableDetailStat.empty())
428     {
429     sprintf(str, "<disableDetailStat value=\"%d\" />\n", req->disableDetailStat.const_data());
430     strcat(r, str);
431     }
432
433 if (!req->alwaysOnline.empty())
434     {
435     sprintf(str, "<aonline value=\"%d\" />\n", req->alwaysOnline.const_data());
436     strcat(r, str);
437     }
438
439 // IP-address of user
440 if (!req->ips.empty())
441     {
442     sprintf(str, "<ip value=\"%s\" />\n", req->ips.const_data().c_str());
443     strcat(r, str);
444     }
445
446 int uPresent = false;
447 int dPresent = false;
448 for (int i = 0; i < DIR_NUM; i++)
449     {
450     if (!req->monthUpload[i].empty())
451         {
452         if (!uPresent && !dPresent)
453             {
454             sprintf(str, "<traff ");
455             strcat(r, str);
456             uPresent = true;
457             }
458
459         stringstream ss;
460         ss << req->monthUpload[i].const_data();
461         //sprintf(str, "MU%d=\"%lld\" ", i, req->u[i].const_data());
462         sprintf(str, "MU%d=\"%s\" ", i, ss.str().c_str());
463         strcat(r, str);
464         }
465     if (!req->monthDownload[i].empty())
466         {
467         if (!uPresent && !dPresent)
468             {
469             sprintf(str, "<traff ");
470             strcat(r, str);
471             dPresent = true;
472             }
473
474         stringstream ss;
475         ss << req->monthDownload[i].const_data();
476         sprintf(str, "MD%d=\"%s\" ", i, ss.str().c_str());
477         strcat(r, str);
478         }
479     if (!req->sessionUpload[i].empty())
480         {
481         if (!uPresent && !dPresent)
482             {
483             sprintf(str, "<traff ");
484             strcat(r, str);
485             uPresent = true;
486             }
487
488         stringstream ss;
489         ss << req->sessionUpload[i].const_data();
490         //sprintf(str, "MU%d=\"%lld\" ", i, req->u[i].const_data());
491         sprintf(str, "MU%d=\"%s\" ", i, ss.str().c_str());
492         strcat(r, str);
493         }
494     if (!req->sessionDownload[i].empty())
495         {
496         if (!uPresent && !dPresent)
497             {
498             sprintf(str, "<traff ");
499             strcat(r, str);
500             dPresent = true;
501             }
502
503         stringstream ss;
504         ss << req->sessionDownload[i].const_data();
505         sprintf(str, "MD%d=\"%s\" ", i, ss.str().c_str());
506         strcat(r, str);
507         }
508     }
509 if (uPresent || dPresent)
510     {
511     strcat(r, "/>");
512     }
513
514 //printf("%s\n", r);
515
516 if (!req->tariff.empty())
517     {
518     switch (req->chgTariff)
519         {
520         case TARIFF_NOW:
521             sprintf(str, "<tariff now=\"%s\"/>\n", req->tariff.const_data().c_str());
522             strcat(r, str);
523             break;
524         case TARIFF_REC:
525             sprintf(str, "<tariff recalc=\"%s\"/>\n", req->tariff.const_data().c_str());
526             strcat(r, str);
527             break;
528         case TARIFF_DEL:
529             sprintf(str, "<tariff delayed=\"%s\"/>\n", req->tariff.const_data().c_str());
530             strcat(r, str);
531             break;
532         }
533
534     }
535
536 if (!req->note.empty())
537     {
538     string note;
539     Encode12str(note, req->note.data());
540     sprintf(str, "<note value=\"%s\"/>", note.c_str());
541     strcat(r, str);
542     }
543
544 if (!req->name.empty())
545     {
546     string name;
547     Encode12str(name, req->name.data());
548     sprintf(str, "<name value=\"%s\"/>", name.c_str());
549     strcat(r, str);
550     }
551
552 if (!req->address.empty())
553     {
554     string address;
555     Encode12str(address, req->address.data());
556     sprintf(str, "<address value=\"%s\"/>", address.c_str());
557     strcat(r, str);
558     }
559
560 if (!req->email.empty())
561     {
562     string email;
563     Encode12str(email, req->email.data());
564     sprintf(str, "<email value=\"%s\"/>", email.c_str());
565     strcat(r, str);
566     }
567
568 if (!req->phone.empty())
569     {
570     string phone;
571     Encode12str(phone, req->phone.data());
572     sprintf(str, "<phone value=\"%s\"/>", phone.c_str());
573     strcat(r, str);
574     }
575
576 if (!req->group.empty())
577     {
578     string group;
579     Encode12str(group, req->group.data());
580     sprintf(str, "<group value=\"%s\"/>", group.c_str());
581     strcat(r, str);
582     }
583
584 for (int i = 0; i < USERDATA_NUM; i++)
585     {
586     if (!req->userData[i].empty())
587         {
588         string ud;
589         Encode12str(ud, req->userData[i].data());
590         sprintf(str, "<userdata%d value=\"%s\"/>", i, ud.c_str());
591         strcat(r, str);
592         }
593     }
594
595 strcat(r, "</SetUser>\n");
596 }
597 //-----------------------------------------------------------------------------
598 int CheckParameters(REQUEST * req)
599 {
600 bool su = false;
601 bool sd = false;
602 bool mu = false;
603 bool md = false;
604 bool ud = false;
605 bool a = !req->admLogin.empty()
606     && !req->admPasswd.empty()
607     && !req->server.empty()
608     && !req->port.empty()
609     && !req->login.empty();
610
611 bool b = !req->cash.empty()
612     || !req->setCash.empty()
613     || !req->credit.empty()
614     || !req->prepaidTraff.empty()
615     || !req->tariff.empty()
616     || !req->usrMsg.empty()
617     || !req->usrPasswd.empty()
618
619     || !req->note.empty()
620     || !req->name.empty()
621     || !req->address.empty()
622     || !req->email.empty()
623     || !req->phone.empty()
624     || !req->group.empty()
625     || !req->ips.empty() // IP-address of user
626
627     || !req->createUser
628     || !req->deleteUser;
629
630
631 for (int i = 0; i < DIR_NUM; i++)
632     {
633     if (req->sessionUpload[i].empty())
634         {
635         su = true;
636         break;
637         }
638     }
639
640 for (int i = 0; i < DIR_NUM; i++)
641     {
642     if (req->sessionDownload[i].empty())
643         {
644         sd = true;
645         break;
646         }
647     }
648
649 for (int i = 0; i < DIR_NUM; i++)
650     {
651     if (req->monthUpload[i].empty())
652         {
653         mu = true;
654         break;
655         }
656     }
657
658 for (int i = 0; i < DIR_NUM; i++)
659     {
660     if (req->monthDownload[i].empty())
661         {
662         md = true;
663         break;
664         }
665     }
666
667 for (int i = 0; i < DIR_NUM; i++)
668     {
669     if (req->userData[i].empty())
670         {
671         ud = true;
672         break;
673         }
674     }
675
676
677 //printf("a=%d, b=%d, u=%d, d=%d ud=%d\n", a, b, u, d, ud);
678 return a && (b || su || sd || mu || md || ud);
679 }
680 //-----------------------------------------------------------------------------
681 int CheckParametersGet(REQUEST * req)
682 {
683 return CheckParameters(req);
684 }
685 //-----------------------------------------------------------------------------
686 int CheckParametersSet(REQUEST * req)
687 {
688 return CheckParameters(req);
689 }
690 //-----------------------------------------------------------------------------
691 bool mainGet(int argc, char **argv)
692 {
693 int c;
694 REQUEST req;
695 RESETABLE<string>   t1;
696 int missedOptionArg = false;
697
698 const char * short_options_get = "s:p:a:w:u:crtmodieNADLPGISOE";
699 int option_index = -1;
700
701 while (1)
702     {
703     option_index = -1;
704     c = getopt_long(argc, argv, short_options_get, long_options_get, &option_index);
705     if (c == -1)
706         break;
707
708     switch (c)
709         {
710         case 's': //server
711             req.server = optarg;
712             break;
713
714         case 'p': //port
715             req.port = ParseServerPort(optarg);
716             //req.portReq = 1;
717             break;
718
719         case 'a': //admin
720             req.admLogin = ParseAdminLogin(optarg);
721             break;
722
723         case 'w': //admin password
724             req.admPasswd = ParsePassword(optarg);
725             break;
726
727         case 'o': //change user password
728             req.usrPasswd = " ";
729             break;
730
731         case 'u': //user
732             req.login = ParseUser(optarg);
733             break;
734
735         case 'c': //get cash
736             req.cash = 1;
737             break;
738
739         case 'r': //credit
740             req.credit = 1;
741             break;
742
743         case 'E': //credit expire
744             req.creditExpire = 1;
745             break;
746
747         case 'd': //down
748             req.down = 1;
749             break;
750
751         case 'i': //passive
752             req.passive = 1;
753             break;
754
755         case 't': //tariff
756             req.tariff = " ";
757             break;
758
759         case 'e': //Prepaid Traffic
760             req.prepaidTraff = 1;
761             break;
762
763         case 'N': //Note
764             req.note = " ";
765             break;
766
767         case 'A': //nAme
768             req.name = " ";
769             break;
770
771         case 'D': //aDdress
772             req.address =" ";
773             break;
774
775         case 'L': //emaiL
776             req.email = " ";
777             break;
778
779         case 'P': //phone
780             req.phone = " ";
781             break;
782
783         case 'G': //Group
784             req.group = " ";
785             break;
786
787         case 'I': //IP-address of user
788             req.ips = " ";
789             break;
790
791         case 'S': //Detail stat status
792             req.disableDetailStat = " ";
793             break;
794
795         case 'O': //Always online status
796             req.alwaysOnline = " ";
797             break;
798
799         case 500: //U
800             SetArrayItem(req.sessionUpload, optarg, 1);
801             //req.sessionUpload[optarg] = 1;
802             break;
803         case 501:
804             SetArrayItem(req.sessionDownload, optarg, 1);
805             //req.sessionDownload[optarg] = 1;
806             break;
807         case 502:
808             SetArrayItem(req.monthUpload, optarg, 1);
809             //req.monthUpload[optarg] = 1;
810             break;
811         case 503:
812             SetArrayItem(req.monthDownload, optarg, 1);
813             //req.monthDownload[optarg] = 1;
814             break;
815
816         case 700: //UserData
817             SetArrayItem(req.userData, optarg, std::string(" "));
818             //req.userData[optarg] = " ";
819             break;
820
821         case 800:
822             req.authBy = true;
823             break;
824
825         case '?':
826         case ':':
827             missedOptionArg = true;
828             break;
829
830         default:
831             printf ("?? getopt returned character code 0%o ??\n", c);
832         }
833     }
834
835 if (optind < argc)
836     {
837     printf ("non-option ARGV-elements: ");
838     while (optind < argc)
839         printf ("%s ", argv[optind++]);
840     UsageInfo();
841     exit(PARAMETER_PARSING_ERR_CODE);
842     }
843
844 if (missedOptionArg || !CheckParametersGet(&req))
845     {
846     //printf("Parameter needed\n");
847     UsageInfo();
848     exit(PARAMETER_PARSING_ERR_CODE);
849     }
850
851 if (req.authBy)
852     return ProcessAuthBy(req.server.data(), req.port.data(), req.admLogin.data(), req.admPasswd.data(), req.login.data());
853 else
854     return ProcessGetUser(req.server.data(), req.port.data(), req.admLogin.data(), req.admPasswd.data(), req.login.data(), req);
855 }
856 //-----------------------------------------------------------------------------
857 bool mainSet(int argc, char **argv)
858 {
859 string str;
860
861 int c;
862 bool isMessage = false;
863 REQUEST req;
864
865 RESETABLE<string>   t1;
866
867 const char * short_options_set = "s:p:a:w:u:c:r:t:m:o:d:i:e:v:nlN:A:D:L:P:G:I:S:O:E:";
868
869 int missedOptionArg = false;
870
871 USER_CONF_RES conf;
872 USER_STAT_RES stat;
873 while (1)
874     {
875     int option_index = -1;
876
877     c = getopt_long(argc, argv, short_options_set, long_options_set, &option_index);
878
879     if (c == -1)
880         break;
881
882     switch (c)
883         {
884         case 's': //server
885             req.server = optarg;
886             break;
887
888         case 'p': //port
889             req.port = ParseServerPort(optarg);
890             //req.portReq = 1;
891             break;
892
893         case 'a': //admin
894             req.admLogin = ParseAdminLogin(optarg);
895             break;
896
897         case 'w': //admin password
898             req.admPasswd = ParsePassword(optarg);
899             break;
900
901         case 'o': //change user password
902             conf.password = ParsePassword(optarg);
903             break;
904
905         case 'u': //user
906             req.login = ParseUser(optarg);
907             break;
908
909         case 'c': //add cash
910             stat.cashAdd = ParseCash(optarg);
911             break;
912
913         case 'v': //set cash
914             stat.cashSet = ParseCash(optarg);
915             break;
916
917         case 'r': //credit
918             conf.credit = ParseCredit(optarg);
919             break;
920
921         case 'E': //credit expire
922             conf.creditExpire = ParseCreditExpire(optarg);
923             break;
924
925         case 'd': //down
926             conf.disabled = ParseDownPassive(optarg);
927             break;
928
929         case 'i': //passive
930             conf.passive = ParseDownPassive(optarg);
931             break;
932
933         case 't': //tariff
934             ParseTariff(optarg, conf.tariffName, conf.nextTariff);
935             break;
936
937         case 'm': //message
938             ParseAnyString(optarg, &str);
939             req.usrMsg = str;
940             isMessage = true;
941             break;
942
943         case 'e': //Prepaid Traffic
944             stat.freeMb = ParsePrepaidTraffic(optarg);
945             break;
946
947         case 'n': //Create User
948             req.createUser = true;
949             break;
950
951         case 'l': //Delete User
952             req.deleteUser = true;
953             break;
954
955         case 'N': //Note
956             ParseAnyString(optarg, &str, "koi8-ru");
957             conf.note = str;
958             break;
959
960         case 'A': //nAme
961             ParseAnyString(optarg, &str, "koi8-ru");
962             conf.realName = str;
963             break;
964
965         case 'D': //aDdress
966             ParseAnyString(optarg, &str, "koi8-ru");
967             conf.address = str;
968             break;
969
970         case 'L': //emaiL
971             ParseAnyString(optarg, &str, "koi8-ru");
972             conf.email = str;
973             break;
974
975         case 'P': //phone
976             ParseAnyString(optarg, &str);
977             conf.phone = str;
978             break;
979
980         case 'G': //Group
981             ParseAnyString(optarg, &str, "koi8-ru");
982             conf.group = str;
983             break;
984
985         case 'I': //IP-address of user
986             ParseAnyString(optarg, &str);
987             conf.ips = StrToIPS(str);
988             break;
989
990         case 'S':
991             conf.disabledDetailStat = ParseDownPassive(optarg);
992             break;
993
994         case 'O':
995             conf.alwaysOnline = ParseDownPassive(optarg);
996             break;
997
998         case 500: //U
999             SetArrayItem(stat.sessionUp, optarg, ParseTraff(argv[optind++]));
1000             break;
1001         case 501:
1002             SetArrayItem(stat.sessionDown, optarg, ParseTraff(argv[optind++]));
1003             break;
1004         case 502:
1005             SetArrayItem(stat.monthUp, optarg, ParseTraff(argv[optind++]));
1006             break;
1007         case 503:
1008             SetArrayItem(stat.monthDown, optarg, ParseTraff(argv[optind++]));
1009             break;
1010
1011         case 700: //UserData
1012             ParseAnyString(argv[optind++], &str);
1013             SetArrayItem(conf.userdata, optarg, str);
1014             break;
1015
1016         case '?':
1017             missedOptionArg = true;
1018             break;
1019
1020         case ':':
1021             missedOptionArg = true;
1022             break;
1023
1024         default:
1025             printf("?? getopt returned character code 0%o ??\n", c);
1026         }
1027     }
1028
1029 if (optind < argc)
1030     {
1031     printf ("non-option ARGV-elements: ");
1032     while (optind < argc)
1033         printf ("%s ", argv[optind++]);
1034     UsageConf();
1035     exit(PARAMETER_PARSING_ERR_CODE);
1036     }
1037
1038 if (missedOptionArg || !CheckParametersSet(&req))
1039     {
1040     //printf("Parameter needed\n");
1041     UsageConf();
1042     exit(PARAMETER_PARSING_ERR_CODE);
1043     }
1044
1045 const int rLen = 20000;
1046 char rstr[rLen];
1047 memset(rstr, 0, rLen);
1048
1049 if (isMessage)
1050     return ProcessSendMessage(req.server.data(), req.port.data(), req.admLogin.data(), req.admPasswd.data(), req.login.data(), req.usrMsg.data());
1051
1052 return ProcessSetUser(req.server.data(), req.port.data(), req.admLogin.data(), req.admPasswd.data(), req.login.data(), conf, stat);
1053 }
1054 //-----------------------------------------------------------------------------
1055 int main(int argc, char **argv)
1056 {
1057 Usage(true);
1058 exit(0);
1059 if (argc <= 2)
1060     {
1061     UsageConf();
1062     exit(PARAMETER_PARSING_ERR_CODE);
1063     }
1064
1065 if (strcmp(argv[1], "get") == 0)
1066     {
1067     //printf("get\n");
1068     return mainGet(argc - 1, argv + 1);
1069     }
1070 else if (strcmp(argv[1], "set") == 0)
1071     {
1072     //printf("set\n");
1073     if (mainSet(argc - 1, argv + 1) )
1074         return 0;
1075     return -1;
1076     }
1077 else
1078     {
1079     UsageConf();
1080     exit(PARAMETER_PARSING_ERR_CODE);
1081     }
1082 return UNKNOWN_ERR_CODE;
1083 }
1084 //-----------------------------------------------------------------------------
1085
1086 namespace
1087 {
1088
1089 void Usage(bool full)
1090 {
1091 std::cout << "sgconf is the Stargazer management utility.\n\n"
1092           << "Usage:\n"
1093           << "\tsgconf [options]\n\n"
1094           << "General options:\n"
1095           << "\t-c, --config <config file>\t\toverride default config file (default: \"~/.config/stg/sgconf.conf\")\n"
1096           << "\t-h, --help\t\t\t\tshow this help and exit\n"
1097           << "\t-h, --help-all\t\t\t\tshow full help and exit\n"
1098           << "\t-v, --version\t\t\t\tshow version information and exit\n\n";
1099 UsageConnection();
1100 UsageAdmins(full);
1101 UsageTariffs(full);
1102 UsageUsers(full);
1103 UsageServices(full);
1104 UsageCorporations(full);
1105 }
1106 //-----------------------------------------------------------------------------
1107 void UsageConnection()
1108 {
1109 std::cout << "Connection options:\n"
1110           << "\t-s, --server <address>\t\t\thost to connect (ip or domain name, default: \"localhost\")\n"
1111           << "\t-p, --port <port>\t\t\tport to connect (default: \"5555\")\n"
1112           << "\t-u, --username <username>\t\tadministrative login (default: \"admin\")\n"
1113           << "\t-w, --userpass <password>\t\tpassword for administrative login\n"
1114           << "\t-a, --address <connection string>\tconnection params as a single string in format: <login>:<password>@<host>:<port>\n\n";
1115 }
1116 //-----------------------------------------------------------------------------
1117 void UsageAdmins(bool full)
1118 {
1119 std::cout << "Admins management options:\n"
1120           << "\t--get-admins\t\t\t\tget a list of admins (subsequent options will define what to show)\n";
1121 if (full)
1122     std::cout << "\t\t--login\t\t\t\tshow admin's login\n"
1123               << "\t\t--priv\t\t\t\tshow admin's priviledges\n\n";
1124 std::cout << "\t--get-admin\t\t\t\tget the information about admin\n";
1125 if (full)
1126     std::cout << "\t\t--login <login>\t\t\tlogin of the admin to show\n"
1127               << "\t\t--priv\t\t\t\tshow admin's priviledges\n\n";
1128 std::cout << "\t--add-admin\t\t\t\tadd a new admin\n";
1129 if (full)
1130     std::cout << "\t\t--login <login>\t\t\tlogin of the admin to add\n"
1131               << "\t\t--password <password>\t\tpassword of the admin to add\n"
1132               << "\t\t--priv <priv number>\t\tpriviledges of the admin to add\n\n";
1133 std::cout << "\t--del-admin\t\t\t\tdelete an existing admin\n";
1134 if (full)
1135     std::cout << "\t\t--login <login>\t\t\tlogin of the admin to delete\n\n";
1136 std::cout << "\t--chg-admin\t\t\t\tchange an existing admin\n";
1137 if (full)
1138     std::cout << "\t\t--login <login>\t\t\tlogin of the admin to change\n"
1139               << "\t\t--priv <priv number>\t\tnew priviledges\n\n";
1140 }
1141 //-----------------------------------------------------------------------------
1142 void UsageTariffs(bool full)
1143 {
1144 std::cout << "Tariffs management options:\n"
1145           << "\t--get-tariffs\t\t\t\tget a list of tariffs (subsequent options will define what to show)\n";
1146 if (full)
1147     std::cout << "\t\t--name\t\t\t\tshow tariff's name\n"
1148               << "\t\t--fee\t\t\t\tshow tariff's fee\n"
1149               << "\t\t--free\t\t\t\tshow tariff's prepaid traffic in terms of cost\n"
1150               << "\t\t--passive-cost\t\t\tshow tariff's cost of \"freeze\"\n"
1151               << "\t\t--traff-type\t\t\tshow what type of traffix will be accounted by the tariff\n"
1152               << "\t\t--dirs\t\t\t\tshow tarification rules for directions\n\n";
1153 std::cout << "\t--get-tariff\t\t\t\tget the information about tariff\n";
1154 if (full)
1155     std::cout << "\t\t--name <name>\t\t\tname of the tariff to show\n"
1156               << "\t\t--fee\t\t\t\tshow tariff's fee\n"
1157               << "\t\t--free\t\t\t\tshow tariff's prepaid traffic in terms of cost\n"
1158               << "\t\t--passive-cost\t\t\tshow tariff's cost of \"freeze\"\n"
1159               << "\t\t--traff-type\t\t\tshow what type of traffix will be accounted by the tariff\n"
1160               << "\t\t--dirs\t\t\t\tshow tarification rules for directions\n\n";
1161 std::cout << "\t--add-tariff\t\t\t\tadd a new tariff\n";
1162 if (full)
1163     std::cout << "\t\t--name <name>\t\t\tname of the tariff to add\n"
1164               << "\t\t--fee <fee>\t\t\tstariff's fee\n"
1165               << "\t\t--free <free>\t\t\ttariff's prepaid traffic in terms of cost\n"
1166               << "\t\t--passive-cost <cost>\t\ttariff's cost of \"freeze\"\n"
1167               << "\t\t--traff-type <type>\t\twhat type of traffi will be accounted by the tariff\n"
1168               << "\t\t--times <times>\t\t\tslash-separated list of \"day\" time-spans (in form \"hh:mm-hh:mm\") for each direction\n"
1169               << "\t\t--prices-day-a <prices>\t\tslash-separated list of prices for \"day\" traffic before threshold for each direction\n"
1170               << "\t\t--prices-night-a <prices>\tslash-separated list of prices for \"night\" traffic before threshold for each direction\n"
1171               << "\t\t--prices-day-b <prices>\t\tslash-separated list of prices for \"day\" traffic after threshold for each direction\n"
1172               << "\t\t--prices-night-b <prices>\tslash-separated list of prices for \"night\" traffic after threshold for each direction\n"
1173               << "\t\t--single-prices <yes|no>\tslash-separated list of \"single price\" flags for each direction\n"
1174               << "\t\t--no-discounts <yes|no>\t\tslash-separated list of \"no discount\" flags for each direction\n"
1175               << "\t\t--thresholds <thresholds>\tslash-separated list of thresholds (in Mb) for each direction\n\n";
1176 std::cout << "\t--del-tariff\t\t\t\tdelete an existing tariff\n";
1177 if (full)
1178     std::cout << "\t\t--name <name>\t\t\tname of the tariff to delete\n\n";
1179 std::cout << "\t--chg-tariff\t\t\t\tchange an existing tariff\n";
1180 if (full)
1181     std::cout << "\t\t--name <name>\t\t\tname of the tariff to change\n"
1182               << "\t\t--fee <fee>\t\t\tstariff's fee\n"
1183               << "\t\t--free <free>\t\t\ttariff's prepaid traffic in terms of cost\n"
1184               << "\t\t--passive-cost <cost>\t\ttariff's cost of \"freeze\"\n"
1185               << "\t\t--traff-type <type>\t\twhat type of traffix will be accounted by the tariff\n"
1186               << "\t\t--dir <N>\t\t\tnumber of direction data to change\n"
1187               << "\t\t\t--time <time>\t\t\"day\" time-span (in form \"hh:mm-hh:mm\")\n"
1188               << "\t\t\t--price-day-a <price>\tprice for \"day\" traffic before threshold\n"
1189               << "\t\t\t--price-night-a <price>\tprice for \"night\" traffic before threshold\n"
1190               << "\t\t\t--price-day-b <price>\tprice for \"day\" traffic after threshold\n"
1191               << "\t\t\t--price-night-b <price>\tprice for \"night\" traffic after threshold\n"
1192               << "\t\t\t--single-price <yes|no>\t\"single price\" flag\n"
1193               << "\t\t\t--no-discount <yes|no>\t\"no discount\" flag\n"
1194               << "\t\t\t--threshold <threshold>\tthreshold (in Mb)\n\n";
1195 }
1196 //-----------------------------------------------------------------------------
1197 void UsageUsers(bool full)
1198 {
1199 std::cout << "Users management options:\n"
1200           << "\t--get-users\t\t\t\tget a list of users (subsequent options will define what to show)\n";
1201 if (full)
1202     std::cout << "\n\n";
1203 std::cout << "\t--get-user\t\t\t\tget the information about user\n";
1204 if (full)
1205     std::cout << "\n\n";
1206 std::cout << "\t--add-user\t\t\t\tadd a new user\n";
1207 if (full)
1208     std::cout << "\n\n";
1209 std::cout << "\t--del-user\t\t\t\tdelete an existing user\n";
1210 if (full)
1211     std::cout << "\n\n";
1212 std::cout << "\t--chg-user\t\t\t\tchange an existing user\n";
1213 if (full)
1214     std::cout << "\n\n";
1215 std::cout << "\t--check-user\t\t\t\tcheck credentials is valid\n";
1216 if (full)
1217     std::cout << "\n\n";
1218 std::cout << "\t--send-message\t\t\t\tsend a message to a user\n";
1219 if (full)
1220     std::cout << "\n\n";
1221 }
1222 //-----------------------------------------------------------------------------
1223 void UsageServices(bool full)
1224 {
1225 std::cout << "Services management options:\n"
1226           << "\t--get-services\t\t\t\tget a list of services (subsequent options will define what to show)\n";
1227 if (full)
1228     std::cout << "\t\t--name\t\t\t\tshow service's name\n"
1229               << "\t\t--comment\t\t\tshow a comment to the service\n"
1230               << "\t\t--cost\t\t\t\tshow service's cost\n"
1231               << "\t\t--pay-day\t\t\tshow service's pay day\n\n";
1232 std::cout << "\t--get-service\t\t\t\tget the information about service\n";
1233 if (full)
1234     std::cout << "\t\t--name <name>\t\t\tname of the service to show\n"
1235               << "\t\t--comment\t\t\tshow a comment to the service\n"
1236               << "\t\t--cost\t\t\t\tshow service's cost\n"
1237               << "\t\t--pay-day\t\t\tshow service's pay day\n\n";
1238 std::cout << "\t--add-service\t\t\t\tadd a new service\n";
1239 if (full)
1240     std::cout << "\t\t--name <name>\t\t\tname of the service to add\n"
1241               << "\t\t--comment <comment>\t\ta comment to the service\n"
1242               << "\t\t--cost <cost>\t\t\tservice's cost\n"
1243               << "\t\t--pay-day <day>\t\t\tservice's pay day\n\n";
1244 std::cout << "\t--del-service\t\t\t\tdelete an existing service\n";
1245 if (full)
1246     std::cout << "\t\t--name <name>\t\t\tname of the service to delete\n\n";
1247 std::cout << "\t--chg-service\t\t\t\tchange an existing service\n";
1248 if (full)
1249     std::cout << "\t\t--name <name>\t\t\tname of the service to change\n"
1250               << "\t\t--comment <comment>\t\ta comment to the service\n"
1251               << "\t\t--cost <cost>\t\t\tservice's cost\n"
1252               << "\t\t--pay-day <day>\t\t\tservice's pay day\n\n";
1253 }
1254 //-----------------------------------------------------------------------------
1255 void UsageCorporations(bool full)
1256 {
1257 std::cout << "Corporations management options:\n"
1258           << "\t--get-corporations\t\t\tget a list of corporations (subsequent options will define what to show)\n";
1259 if (full)
1260     std::cout << "\t\t--name\t\t\t\tshow corporation's name\n"
1261               << "\t\t--cash\t\t\t\tshow corporation's cash\n\n";
1262 std::cout << "\t--get-corp\t\t\t\tget the information about corporation\n";
1263 if (full)
1264     std::cout << "\t\t--name <name>\t\t\tname of the corporation to show\n"
1265               << "\t\t--cash\t\t\t\tshow corporation's cash\n\n";
1266 std::cout << "\t--add-corp\t\t\t\tadd a new corporation\n";
1267 if (full)
1268     std::cout << "\t\t--name <name>\t\t\tname of the corporation to add\n"
1269               << "\t\t--cash <cash>\t\t\tinitial corporation's cash (default: \"0\")\n\n";
1270 std::cout << "\t--del-corp\t\t\t\tdelete an existing corporation\n";
1271 if (full)
1272     std::cout << "\t\t--name <name>\t\t\tname of the corporation to delete\n\n";
1273 std::cout << "\t--chg-corp\t\t\t\tchange an existing corporation\n";
1274 if (full)
1275     std::cout << "\t\t--name <name>\t\t\tname of the corporation to change\n"
1276               << "\t\t--add-cash <amount>[:<message>]\tadd cash to the corporation's account and optional comment message\n"
1277               << "\t\t--set-cash <cash>[:<message>]\tnew corporation's cash and optional comment message\n\n";
1278 }
1279
1280 } // namespace anonymous