]> git.stg.codes - stg.git/blob - projects/sgconf/main.cpp
Added COMMAND_FUNCTOR and COMMAND_ACTION.
[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  *    Author : Maxim Mamontov <faust@stargazer.dp.ua>
20  */
21
22 #include "request.h"
23 #include "common_sg.h"
24 #include "sg_error_codes.h"
25
26 #include "xml.h"
27 #include "options.h"
28 #include "actions.h"
29 #include "config.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 struct nullary_function
71 {
72 typedef T result_type;
73 };
74
75 template <typename F>
76 class binder0 : public nullary_function<typename F::result_type>
77 {
78     public:
79         binder0(const F & func, const typename F::argument_type & arg)
80             : m_func(func), m_arg(arg) {}
81         typename F::result_type operator()() const { return m_func(m_arg); }
82     private:
83         F m_func;
84         typename F::argument_type m_arg;
85 };
86
87 template <typename F>
88 inline
89 binder0<F> bind0(const F & func, const typename F::argument_type & arg)
90 {
91 return binder0<F>(func, arg);
92 }
93
94 template <typename C, typename A, typename R>
95 class METHOD1_ADAPTER : public std::unary_function<A, R>
96 {
97     public:
98         METHOD1_ADAPTER(R (C::* func)(A), C & obj) : m_func(func), m_obj(obj) {}
99         R operator()(A arg) { return (m_obj.*m_func)(arg); }
100     private:
101         R (C::* m_func)(A);
102         C & m_obj;
103 };
104
105 template <typename C, typename A, typename R>
106 class CONST_METHOD1_ADAPTER : public std::unary_function<A, R>
107 {
108     public:
109         CONST_METHOD1_ADAPTER(R (C::* func)(A) const, C & obj) : m_func(func), m_obj(obj) {}
110         R operator()(A arg) const { return (m_obj.*m_func)(arg); }
111     private:
112         R (C::* m_func)(A) const;
113         C & m_obj;
114 };
115
116 template <typename C, typename A, typename R>
117 METHOD1_ADAPTER<C, A, R> Method1Adapt(R (C::* func)(A), C & obj)
118 {
119 return METHOD1_ADAPTER<C, A, R>(func, obj);
120 }
121
122 template <typename C, typename A, typename R>
123 CONST_METHOD1_ADAPTER<C, A, R> Method1Adapt(R (C::* func)(A) const, C & obj)
124 {
125 return CONST_METHOD1_ADAPTER<C, A, R>(func, obj);
126 }
127
128 template <typename T>
129 bool SetArrayItem(T & array, const char * index, const typename ARRAY_TYPE<T>::type & value)
130 {
131 size_t pos = 0;
132 if (str2x(index, pos))
133     return false;
134 array[pos] = value;
135 return true;
136 }
137
138 void RawXMLCallback(bool result, const std::string & reason, const std::string & response, void * data)
139 {
140 if (!result)
141     {
142     std::cerr << "Failed to get raw XML response. Reason: '" << reason << "'." << std::endl;
143     return;
144     }
145 PrintXML(response);
146 }
147
148 void Usage();
149 void UsageAll();
150 void UsageImpl(bool full);
151 void UsageConnection();
152 void UsageAdmins(bool full);
153 void UsageTariffs(bool full);
154 void UsageUsers(bool full);
155 void UsageServices(bool full);
156 void UsageCorporations(bool full);
157
158 void Version();
159
160 void ReadUserConfigFile(SGCONF::OPTION_BLOCK & block)
161 {
162 std::vector<std::string> paths;
163 const char * configHome = getenv("XDG_CONFIG_HOME");
164 if (configHome == NULL)
165     {
166     const char * home = getenv("HOME");
167     if (home == NULL)
168         return;
169     paths.push_back(std::string(home) + "/.config/sgconf/sgconf.conf");
170     paths.push_back(std::string(home) + "/.sgconf/sgconf.conf");
171     }
172 else
173     paths.push_back(std::string(configHome) + "/sgconf/sgconf.conf");
174 for (std::vector<std::string>::const_iterator it = paths.begin(); it != paths.end(); ++it)
175     if (access(it->c_str(), R_OK) == 0)
176         {
177         block.ParseFile(*it);
178         return;
179         }
180 }
181
182 } // namespace anonymous
183
184 namespace SGCONF
185 {
186
187 class CONFIG_ACTION : public ACTION
188 {
189     public:
190         CONFIG_ACTION(CONFIG & config,
191                       const std::string & paramDescription)
192             : m_config(config),
193               m_description(paramDescription)
194         {}
195
196         virtual ACTION * Clone() const { return new CONFIG_ACTION(*this); }
197
198         virtual std::string ParamDescription() const { return m_description; }
199         virtual std::string DefaultDescription() const { return ""; }
200         virtual OPTION_BLOCK & Suboptions() { return m_suboptions; }
201         virtual PARSER_STATE Parse(int argc, char ** argv);
202
203     private:
204         CONFIG & m_config;
205         std::string m_description;
206         OPTION_BLOCK m_suboptions;
207
208         void ParseCredentials(const std::string & credentials);
209         void ParseHostAndPort(const std::string & hostAndPort);
210 };
211
212 class COMMAND_FUNCTOR
213 {
214     public:
215         virtual ~COMMAND_FUNCTOR() {}
216         virtual bool operator()(const std::string& arg, const std::map<std::string, std::string>& options) = 0;
217 };
218
219 class COMMAND_ACTION : public ACTION
220 {
221     public:
222         COMMAND_ACTION(CONFIG & config,
223                        const std::string & paramDescription,
224                        bool needArgument,
225                        const OPTION_BLOCK& suboptions,
226                        COMMAND_FUNCTOR* funPtr)
227             : m_config(config),
228               m_description(paramDescription),
229               m_argument(needArgument),
230               m_suboptions(suboptions),
231               m_funPtr(funPtr)
232         {}
233
234         virtual ACTION * Clone() const { return new COMMAND_ACTION(*this); }
235
236         virtual std::string ParamDescription() const { return m_description; }
237         virtual std::string DefaultDescription() const { return ""; }
238         virtual OPTION_BLOCK & Suboptions() { return m_suboptions; }
239         virtual PARSER_STATE Parse(int argc, char ** argv)
240         {
241         PARSER_STATE state(false, argc, argv);
242         if (m_argument)
243             {
244             if (argc == 0 ||
245                 argv == NULL ||
246                 *argv == NULL)
247                 throw ERROR("Missing argument.");
248             m_argument = *argv;
249             --state.argc;
250             ++state.argv;
251             }
252         std::list<OPTION_BLOCK>::iterator it(m_suboptions.begin());
253         while (!state.stop && it != m_suboptions.end())
254             {
255             state = it->Parse(state.argc, state.argv);
256             ++it;
257             }
258         m_funPtr(m_argument, m_params);
259         return state;
260         }
261
262     private:
263         CONFIG & m_config;
264         std::string m_description;
265         bool m_needArgument;
266         std::string m_argument;
267         OPTION_BLOCK m_suboptions;
268         std::map<std::string, std::string> m_params;
269         COMMAND_FUNCTOR* m_funPtr;
270 };
271
272 PARSER_STATE CONFIG_ACTION::Parse(int argc, char ** argv)
273 {
274 if (argc == 0 ||
275     argv == NULL ||
276     *argv == NULL)
277     throw ERROR("Missing argument.");
278 char * pos = strchr(*argv, '@');
279 if (pos != NULL)
280     {
281     ParseCredentials(std::string(*argv, pos));
282     ParseHostAndPort(std::string(pos + 1));
283     }
284 else
285     {
286     ParseHostAndPort(std::string(*argv));
287     }
288 return PARSER_STATE(false, --argc, ++argv);
289 }
290
291 void CONFIG_ACTION::ParseCredentials(const std::string & credentials)
292 {
293 std::string::size_type pos = credentials.find_first_of(':');
294 if (pos != std::string::npos)
295     {
296     m_config.userName = credentials.substr(0, pos);
297     m_config.userPass = credentials.substr(pos + 1);
298     }
299 else
300     {
301     m_config.userName = credentials;
302     }
303 }
304
305 void CONFIG_ACTION::ParseHostAndPort(const std::string & hostAndPort)
306 {
307 std::string::size_type pos = hostAndPort.find_first_of(':');
308 if (pos != std::string::npos)
309     {
310     m_config.server = hostAndPort.substr(0, pos);
311     uint16_t port = 0;
312     if (str2x(hostAndPort.substr(pos + 1), port))
313         throw ERROR("Invalid port value: '" + hostAndPort.substr(pos + 1) + "'");
314     m_config.port = port;
315     }
316 else
317     {
318     m_config.server = hostAndPort;
319     }
320 }
321
322 inline
323 CONFIG_ACTION * MakeParamAction(CONFIG & config,
324                                 const std::string & paramDescription)
325 {
326 return new CONFIG_ACTION(config, paramDescription);
327 }
328
329 } // namespace SGCONF
330
331 time_t stgTime;
332
333 struct option long_options_get[] = {
334 {"server",      1, 0, 's'},  //Server
335 {"port",        1, 0, 'p'},  //Port
336 {"admin",       1, 0, 'a'},  //Admin
337 {"admin_pass",  1, 0, 'w'},  //passWord
338 {"user",        1, 0, 'u'},  //User
339 {"addcash",     0, 0, 'c'},  //Add Cash
340 //{"setcash",     0, 0, 'v'},  //Set Cash
341 {"credit",      0, 0, 'r'},  //cRedit
342 {"tariff",      0, 0, 't'},  //Tariff
343 {"message",     0, 0, 'm'},  //message
344 {"password",    0, 0, 'o'},  //password
345 {"down",        0, 0, 'd'},  //down
346 {"passive",     0, 0, 'i'},  //passive
347 {"disable-stat",0, 0, 'S'},  //disable detail stat
348 {"always-online",0, 0, 'O'}, //always online
349 {"session-upload",   1, 0, 500},  //SU0
350 {"session-download", 1, 0, 501},  //SD0
351 {"month-upload",     1, 0, 502},  //MU0
352 {"month-download",   1, 0, 503},  //MD0
353
354 {"user-data",   1, 0, 700},  //UserData0
355
356 {"prepaid",     0, 0, 'e'},  //prepaid traff
357 {"create",      0, 0, 'n'},  //create
358 {"delete",      0, 0, 'l'},  //delete
359
360 {"note",        0, 0, 'N'},  //Note
361 {"name",        0, 0, 'A'},  //nAme
362 {"address",     0, 0, 'D'},  //aDdress
363 {"email",       0, 0, 'L'},  //emaiL
364 {"phone",       0, 0, 'P'},  //phone
365 {"group",       0, 0, 'G'},  //Group
366 {"ip",          0, 0, 'I'},  //IP-address of user
367 {"authorized-by",0, 0, 800}, //always online
368
369 {0, 0, 0, 0}};
370
371 struct option long_options_set[] = {
372 {"server",      1, 0, 's'},  //Server
373 {"port",        1, 0, 'p'},  //Port
374 {"admin",       1, 0, 'a'},  //Admin
375 {"admin_pass",  1, 0, 'w'},  //passWord
376 {"user",        1, 0, 'u'},  //User
377 {"addcash",     1, 0, 'c'},  //Add Cash
378 {"setcash",     1, 0, 'v'},  //Set Cash
379 {"credit",      1, 0, 'r'},  //cRedit
380 {"tariff",      1, 0, 't'},  //Tariff
381 {"message",     1, 0, 'm'},  //message
382 {"password",    1, 0, 'o'},  //password
383 {"down",        1, 0, 'd'},  //down
384 {"passive",     1, 0, 'i'},  //passive
385 {"disable-stat",1, 0, 'S'},  //disable detail stat
386 {"always-online",1, 0, 'O'},  //always online
387 {"session-upload",   1, 0, 500},  //U0
388 {"session-download", 1, 0, 501},  //U1
389 {"month-upload",     1, 0, 502},  //U2
390 {"month-download",   1, 0, 503},  //U3
391
392 {"user-data",        1, 0, 700},  //UserData
393
394 {"prepaid",     1, 0, 'e'},  //prepaid traff
395 {"create",      1, 0, 'n'},  //create
396 {"delete",      1, 0, 'l'},  //delete
397
398 {"note",        1, 0, 'N'},  //Note
399 {"name",        1, 0, 'A'},  //nAme
400 {"address",     1, 0, 'D'},  //aDdress
401 {"email",       1, 0, 'L'},  //emaiL
402 {"phone",       1, 0, 'P'},  //phone
403 {"group",       1, 0, 'G'},  //Group
404 {"ip",          0, 0, 'I'},  //IP-address of user
405
406 {0, 0, 0, 0}};
407
408 //-----------------------------------------------------------------------------
409 CASH_INFO ParseCash(const char * str)
410 {
411 //-c 123.45:log message
412 std::string cashString;
413 std::string message;
414 const char * pos = strchr(str, ':');
415 if (pos != NULL)
416     {
417     cashString.append(str, pos);
418     message.append(pos + 1);
419     }
420 else
421     cashString = str;
422
423 double cash = 0;
424 if (strtodouble2(cashString, cash) != 0)
425     {
426     printf("Incorrect cash value %s\n", str);
427     exit(PARAMETER_PARSING_ERR_CODE);
428     }
429
430 return CASH_INFO(cash, message);
431 }
432 //-----------------------------------------------------------------------------
433 double ParseCredit(const char * c)
434 {
435 double credit;
436 if (strtodouble2(c, credit) != 0)
437     {
438     printf("Incorrect credit value %s\n", c);
439     exit(PARAMETER_PARSING_ERR_CODE);
440     }
441
442 return credit;
443 }
444 //-----------------------------------------------------------------------------
445 double ParsePrepaidTraffic(const char * c)
446 {
447 double credit;
448 if (strtodouble2(c, credit) != 0)
449     {
450     printf("Incorrect prepaid traffic value %s\n", c);
451     exit(PARAMETER_PARSING_ERR_CODE);
452     }
453
454 return credit;
455 }
456 //-----------------------------------------------------------------------------
457 int64_t ParseTraff(const char * c)
458 {
459 int64_t traff;
460 if (str2x(c, traff) != 0)
461     {
462     printf("Incorrect credit value %s\n", c);
463     exit(PARAMETER_PARSING_ERR_CODE);
464     }
465
466 return traff;
467 }
468 //-----------------------------------------------------------------------------
469 bool ParseDownPassive(const char * dp)
470 {
471 if (!(dp[1] == 0 && (dp[0] == '1' || dp[0] == '0')))
472     {
473     printf("Incorrect value %s\n", dp);
474     exit(PARAMETER_PARSING_ERR_CODE);
475     }
476
477 return dp[0] - '0';
478 }
479 //-----------------------------------------------------------------------------
480 void ParseTariff(const char * str, RESETABLE<std::string> & tariffName, RESETABLE<std::string> & nextTariff)
481 {
482 const char * pos = strchr(str, ':');
483 if (pos != NULL)
484     {
485     std::string tariff(str, pos);
486     if (strcmp(pos + 1, "now") == 0)
487         tariffName = tariff;
488     else if (strcmp(pos + 1, "delayed") == 0)
489         nextTariff = tariff;
490     else
491         {
492         printf("Incorrect tariff value '%s'. Should be '<tariff>', '<tariff>:now' or '<tariff>:delayed'.\n", str);
493         exit(PARAMETER_PARSING_ERR_CODE);
494         }
495     }
496 else
497     tariffName = str;
498 }
499 //-----------------------------------------------------------------------------
500 time_t ParseCreditExpire(const char * str)
501 {
502 struct tm brokenTime;
503
504 brokenTime.tm_wday = 0;
505 brokenTime.tm_yday = 0;
506 brokenTime.tm_isdst = 0;
507 brokenTime.tm_hour = 0;
508 brokenTime.tm_min = 0;
509 brokenTime.tm_sec = 0;
510
511 stg_strptime(str, "%Y-%m-%d", &brokenTime);
512
513 return stg_timegm(&brokenTime);
514 }
515 //-----------------------------------------------------------------------------
516 void ParseAnyString(const char * c, string * msg, const char * enc)
517 {
518 iconv_t cd;
519 char * ob = new char[strlen(c) + 1];
520 char * ib = new char[strlen(c) + 1];
521
522 strcpy(ib, c);
523
524 char * outbuf = ob;
525 char * inbuf = ib;
526
527 setlocale(LC_ALL, "");
528
529 char charsetF[255];
530 strncpy(charsetF, nl_langinfo(CODESET), 255);
531
532 const char * charsetT = enc;
533
534 size_t nconv = 1;
535
536 size_t insize = strlen(ib);
537 size_t outsize = strlen(ib);
538
539 insize = strlen(c);
540
541 cd = iconv_open(charsetT, charsetF);
542 if (cd == (iconv_t) -1)
543     {
544     if (errno == EINVAL)
545         {
546         printf("Warning: iconv from %s to %s failed\n", charsetF, charsetT);
547         *msg = c;
548         return;
549         }
550     else
551         printf("error iconv_open\n");
552
553     exit(ICONV_ERR_CODE);
554     }
555
556 #if defined(FREE_BSD) || defined(FREE_BSD5)
557 nconv = iconv (cd, (const char**)&inbuf, &insize, &outbuf, &outsize);
558 #else
559 nconv = iconv (cd, &inbuf, &insize, &outbuf, &outsize);
560 #endif
561 //printf("nconv=%d outsize=%d\n", nconv, outsize);
562 if (nconv == (size_t) -1)
563     {
564     if (errno != EINVAL)
565         {
566         printf("iconv error\n");
567         exit(ICONV_ERR_CODE);
568         }
569     }
570
571 *outbuf = L'\0';
572
573 iconv_close(cd);
574 *msg = ob;
575
576 delete[] ob;
577 delete[] ib;
578 }
579 //-----------------------------------------------------------------------------
580 void CreateRequestSet(REQUEST * req, char * r)
581 {
582 const int strLen = 10024;
583 char str[strLen];
584 memset(str, 0, strLen);
585
586 r[0] = 0;
587
588 if (!req->usrMsg.empty())
589     {
590     string msg;
591     Encode12str(msg, req->usrMsg.data());
592     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());
593     //sprintf(str, "<message login=\"%s\" priority=\"0\" text=\"%s\"/>\n", req->login, msg);
594     strcat(r, str);
595     return;
596     }
597
598 if (req->deleteUser)
599     {
600     sprintf(str, "<DelUser login=\"%s\"/>", req->login.const_data().c_str());
601     strcat(r, str);
602     //printf("%s\n", r);
603     return;
604     }
605
606 if (req->createUser)
607     {
608     sprintf(str, "<AddUser> <login value=\"%s\"/> </AddUser>", req->login.const_data().c_str());
609     strcat(r, str);
610     //printf("%s\n", r);
611     return;
612     }
613
614 strcat(r, "<SetUser>\n");
615 sprintf(str, "<login value=\"%s\"/>\n", req->login.const_data().c_str());
616 strcat(r, str);
617 if (!req->credit.empty())
618     {
619     sprintf(str, "<credit value=\"%f\"/>\n", req->credit.const_data());
620     strcat(r, str);
621     }
622
623 if (!req->creditExpire.empty())
624     {
625     sprintf(str, "<creditExpire value=\"%ld\"/>\n", req->creditExpire.const_data());
626     strcat(r, str);
627     }
628
629 if (!req->prepaidTraff.empty())
630     {
631     sprintf(str, "<FreeMb value=\"%f\"/>\n", req->prepaidTraff.const_data());
632     strcat(r, str);
633     }
634
635 if (!req->cash.empty())
636     {
637     string msg;
638     Encode12str(msg, req->message);
639     sprintf(str, "<cash add=\"%f\" msg=\"%s\"/>\n", req->cash.const_data(), msg.c_str());
640     strcat(r, str);
641     }
642
643 if (!req->setCash.empty())
644     {
645     string msg;
646     Encode12str(msg, req->message);
647     sprintf(str, "<cash set=\"%f\" msg=\"%s\"/>\n", req->setCash.const_data(), msg.c_str());
648     strcat(r, str);
649     }
650
651 if (!req->usrPasswd.empty())
652     {
653     sprintf(str, "<password value=\"%s\" />\n", req->usrPasswd.const_data().c_str());
654     strcat(r, str);
655     }
656
657 if (!req->down.empty())
658     {
659     sprintf(str, "<down value=\"%d\" />\n", req->down.const_data());
660     strcat(r, str);
661     }
662
663 if (!req->passive.empty())
664     {
665     sprintf(str, "<passive value=\"%d\" />\n", req->passive.const_data());
666     strcat(r, str);
667     }
668
669 if (!req->disableDetailStat.empty())
670     {
671     sprintf(str, "<disableDetailStat value=\"%d\" />\n", req->disableDetailStat.const_data());
672     strcat(r, str);
673     }
674
675 if (!req->alwaysOnline.empty())
676     {
677     sprintf(str, "<aonline value=\"%d\" />\n", req->alwaysOnline.const_data());
678     strcat(r, str);
679     }
680
681 // IP-address of user
682 if (!req->ips.empty())
683     {
684     sprintf(str, "<ip value=\"%s\" />\n", req->ips.const_data().c_str());
685     strcat(r, str);
686     }
687
688 int uPresent = false;
689 int dPresent = false;
690 for (int i = 0; i < DIR_NUM; i++)
691     {
692     if (!req->monthUpload[i].empty())
693         {
694         if (!uPresent && !dPresent)
695             {
696             sprintf(str, "<traff ");
697             strcat(r, str);
698             uPresent = true;
699             }
700
701         stringstream ss;
702         ss << req->monthUpload[i].const_data();
703         //sprintf(str, "MU%d=\"%lld\" ", i, req->u[i].const_data());
704         sprintf(str, "MU%d=\"%s\" ", i, ss.str().c_str());
705         strcat(r, str);
706         }
707     if (!req->monthDownload[i].empty())
708         {
709         if (!uPresent && !dPresent)
710             {
711             sprintf(str, "<traff ");
712             strcat(r, str);
713             dPresent = true;
714             }
715
716         stringstream ss;
717         ss << req->monthDownload[i].const_data();
718         sprintf(str, "MD%d=\"%s\" ", i, ss.str().c_str());
719         strcat(r, str);
720         }
721     if (!req->sessionUpload[i].empty())
722         {
723         if (!uPresent && !dPresent)
724             {
725             sprintf(str, "<traff ");
726             strcat(r, str);
727             uPresent = true;
728             }
729
730         stringstream ss;
731         ss << req->sessionUpload[i].const_data();
732         //sprintf(str, "MU%d=\"%lld\" ", i, req->u[i].const_data());
733         sprintf(str, "MU%d=\"%s\" ", i, ss.str().c_str());
734         strcat(r, str);
735         }
736     if (!req->sessionDownload[i].empty())
737         {
738         if (!uPresent && !dPresent)
739             {
740             sprintf(str, "<traff ");
741             strcat(r, str);
742             dPresent = true;
743             }
744
745         stringstream ss;
746         ss << req->sessionDownload[i].const_data();
747         sprintf(str, "MD%d=\"%s\" ", i, ss.str().c_str());
748         strcat(r, str);
749         }
750     }
751 if (uPresent || dPresent)
752     {
753     strcat(r, "/>");
754     }
755
756 //printf("%s\n", r);
757
758 if (!req->tariff.empty())
759     {
760     switch (req->chgTariff)
761         {
762         case TARIFF_NOW:
763             sprintf(str, "<tariff now=\"%s\"/>\n", req->tariff.const_data().c_str());
764             strcat(r, str);
765             break;
766         case TARIFF_REC:
767             sprintf(str, "<tariff recalc=\"%s\"/>\n", req->tariff.const_data().c_str());
768             strcat(r, str);
769             break;
770         case TARIFF_DEL:
771             sprintf(str, "<tariff delayed=\"%s\"/>\n", req->tariff.const_data().c_str());
772             strcat(r, str);
773             break;
774         }
775
776     }
777
778 if (!req->note.empty())
779     {
780     string note;
781     Encode12str(note, req->note.data());
782     sprintf(str, "<note value=\"%s\"/>", note.c_str());
783     strcat(r, str);
784     }
785
786 if (!req->name.empty())
787     {
788     string name;
789     Encode12str(name, req->name.data());
790     sprintf(str, "<name value=\"%s\"/>", name.c_str());
791     strcat(r, str);
792     }
793
794 if (!req->address.empty())
795     {
796     string address;
797     Encode12str(address, req->address.data());
798     sprintf(str, "<address value=\"%s\"/>", address.c_str());
799     strcat(r, str);
800     }
801
802 if (!req->email.empty())
803     {
804     string email;
805     Encode12str(email, req->email.data());
806     sprintf(str, "<email value=\"%s\"/>", email.c_str());
807     strcat(r, str);
808     }
809
810 if (!req->phone.empty())
811     {
812     string phone;
813     Encode12str(phone, req->phone.data());
814     sprintf(str, "<phone value=\"%s\"/>", phone.c_str());
815     strcat(r, str);
816     }
817
818 if (!req->group.empty())
819     {
820     string group;
821     Encode12str(group, req->group.data());
822     sprintf(str, "<group value=\"%s\"/>", group.c_str());
823     strcat(r, str);
824     }
825
826 for (int i = 0; i < USERDATA_NUM; i++)
827     {
828     if (!req->userData[i].empty())
829         {
830         string ud;
831         Encode12str(ud, req->userData[i].data());
832         sprintf(str, "<userdata%d value=\"%s\"/>", i, ud.c_str());
833         strcat(r, str);
834         }
835     }
836
837 strcat(r, "</SetUser>\n");
838 }
839 //-----------------------------------------------------------------------------
840 int CheckParameters(REQUEST * req)
841 {
842 bool su = false;
843 bool sd = false;
844 bool mu = false;
845 bool md = false;
846 bool ud = false;
847 bool a = !req->admLogin.empty()
848     && !req->admPasswd.empty()
849     && !req->server.empty()
850     && !req->port.empty()
851     && !req->login.empty();
852
853 bool b = !req->cash.empty()
854     || !req->setCash.empty()
855     || !req->credit.empty()
856     || !req->prepaidTraff.empty()
857     || !req->tariff.empty()
858     || !req->usrMsg.empty()
859     || !req->usrPasswd.empty()
860
861     || !req->note.empty()
862     || !req->name.empty()
863     || !req->address.empty()
864     || !req->email.empty()
865     || !req->phone.empty()
866     || !req->group.empty()
867     || !req->ips.empty() // IP-address of user
868
869     || !req->createUser
870     || !req->deleteUser;
871
872
873 for (int i = 0; i < DIR_NUM; i++)
874     {
875     if (req->sessionUpload[i].empty())
876         {
877         su = true;
878         break;
879         }
880     }
881
882 for (int i = 0; i < DIR_NUM; i++)
883     {
884     if (req->sessionDownload[i].empty())
885         {
886         sd = true;
887         break;
888         }
889     }
890
891 for (int i = 0; i < DIR_NUM; i++)
892     {
893     if (req->monthUpload[i].empty())
894         {
895         mu = true;
896         break;
897         }
898     }
899
900 for (int i = 0; i < DIR_NUM; i++)
901     {
902     if (req->monthDownload[i].empty())
903         {
904         md = true;
905         break;
906         }
907     }
908
909 for (int i = 0; i < DIR_NUM; i++)
910     {
911     if (req->userData[i].empty())
912         {
913         ud = true;
914         break;
915         }
916     }
917
918
919 //printf("a=%d, b=%d, u=%d, d=%d ud=%d\n", a, b, u, d, ud);
920 return a && (b || su || sd || mu || md || ud);
921 }
922 //-----------------------------------------------------------------------------
923 int CheckParametersGet(REQUEST * req)
924 {
925 return CheckParameters(req);
926 }
927 //-----------------------------------------------------------------------------
928 int CheckParametersSet(REQUEST * req)
929 {
930 return CheckParameters(req);
931 }
932 //-----------------------------------------------------------------------------
933 bool mainGet(int argc, char **argv)
934 {
935 int c;
936 REQUEST req;
937 RESETABLE<string>   t1;
938 int missedOptionArg = false;
939
940 const char * short_options_get = "s:p:a:w:u:crtmodieNADLPGISOE";
941 int option_index = -1;
942
943 while (1)
944     {
945     option_index = -1;
946     c = getopt_long(argc, argv, short_options_get, long_options_get, &option_index);
947     if (c == -1)
948         break;
949
950     switch (c)
951         {
952         case 's': //server
953             req.server = optarg;
954             break;
955
956         case 'p': //port
957             req.port = ParseServerPort(optarg);
958             //req.portReq = 1;
959             break;
960
961         case 'a': //admin
962             req.admLogin = ParseAdminLogin(optarg);
963             break;
964
965         case 'w': //admin password
966             req.admPasswd = ParsePassword(optarg);
967             break;
968
969         case 'o': //change user password
970             req.usrPasswd = " ";
971             break;
972
973         case 'u': //user
974             req.login = ParseUser(optarg);
975             break;
976
977         case 'c': //get cash
978             req.cash = 1;
979             break;
980
981         case 'r': //credit
982             req.credit = 1;
983             break;
984
985         case 'E': //credit expire
986             req.creditExpire = 1;
987             break;
988
989         case 'd': //down
990             req.down = 1;
991             break;
992
993         case 'i': //passive
994             req.passive = 1;
995             break;
996
997         case 't': //tariff
998             req.tariff = " ";
999             break;
1000
1001         case 'e': //Prepaid Traffic
1002             req.prepaidTraff = 1;
1003             break;
1004
1005         case 'N': //Note
1006             req.note = " ";
1007             break;
1008
1009         case 'A': //nAme
1010             req.name = " ";
1011             break;
1012
1013         case 'D': //aDdress
1014             req.address =" ";
1015             break;
1016
1017         case 'L': //emaiL
1018             req.email = " ";
1019             break;
1020
1021         case 'P': //phone
1022             req.phone = " ";
1023             break;
1024
1025         case 'G': //Group
1026             req.group = " ";
1027             break;
1028
1029         case 'I': //IP-address of user
1030             req.ips = " ";
1031             break;
1032
1033         case 'S': //Detail stat status
1034             req.disableDetailStat = " ";
1035             break;
1036
1037         case 'O': //Always online status
1038             req.alwaysOnline = " ";
1039             break;
1040
1041         case 500: //U
1042             SetArrayItem(req.sessionUpload, optarg, 1);
1043             //req.sessionUpload[optarg] = 1;
1044             break;
1045         case 501:
1046             SetArrayItem(req.sessionDownload, optarg, 1);
1047             //req.sessionDownload[optarg] = 1;
1048             break;
1049         case 502:
1050             SetArrayItem(req.monthUpload, optarg, 1);
1051             //req.monthUpload[optarg] = 1;
1052             break;
1053         case 503:
1054             SetArrayItem(req.monthDownload, optarg, 1);
1055             //req.monthDownload[optarg] = 1;
1056             break;
1057
1058         case 700: //UserData
1059             SetArrayItem(req.userData, optarg, std::string(" "));
1060             //req.userData[optarg] = " ";
1061             break;
1062
1063         case 800:
1064             req.authBy = true;
1065             break;
1066
1067         case '?':
1068         case ':':
1069             missedOptionArg = true;
1070             break;
1071
1072         default:
1073             printf ("?? getopt returned character code 0%o ??\n", c);
1074         }
1075     }
1076
1077 if (optind < argc)
1078     {
1079     printf ("non-option ARGV-elements: ");
1080     while (optind < argc)
1081         printf ("%s ", argv[optind++]);
1082     UsageInfo();
1083     exit(PARAMETER_PARSING_ERR_CODE);
1084     }
1085
1086 if (missedOptionArg || !CheckParametersGet(&req))
1087     {
1088     //printf("Parameter needed\n");
1089     UsageInfo();
1090     exit(PARAMETER_PARSING_ERR_CODE);
1091     }
1092
1093 if (req.authBy)
1094     return ProcessAuthBy(req.server.data(), req.port.data(), req.admLogin.data(), req.admPasswd.data(), req.login.data());
1095 else
1096     return ProcessGetUser(req.server.data(), req.port.data(), req.admLogin.data(), req.admPasswd.data(), req.login.data(), req);
1097 }
1098 //-----------------------------------------------------------------------------
1099 bool mainSet(int argc, char **argv)
1100 {
1101 string str;
1102
1103 int c;
1104 bool isMessage = false;
1105 REQUEST req;
1106
1107 RESETABLE<string>   t1;
1108
1109 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:";
1110
1111 int missedOptionArg = false;
1112
1113 USER_CONF_RES conf;
1114 USER_STAT_RES stat;
1115 while (1)
1116     {
1117     int option_index = -1;
1118
1119     c = getopt_long(argc, argv, short_options_set, long_options_set, &option_index);
1120
1121     if (c == -1)
1122         break;
1123
1124     switch (c)
1125         {
1126         case 's': //server
1127             req.server = optarg;
1128             break;
1129
1130         case 'p': //port
1131             req.port = ParseServerPort(optarg);
1132             //req.portReq = 1;
1133             break;
1134
1135         case 'a': //admin
1136             req.admLogin = ParseAdminLogin(optarg);
1137             break;
1138
1139         case 'w': //admin password
1140             req.admPasswd = ParsePassword(optarg);
1141             break;
1142
1143         case 'o': //change user password
1144             conf.password = ParsePassword(optarg);
1145             break;
1146
1147         case 'u': //user
1148             req.login = ParseUser(optarg);
1149             break;
1150
1151         case 'c': //add cash
1152             stat.cashAdd = ParseCash(optarg);
1153             break;
1154
1155         case 'v': //set cash
1156             stat.cashSet = ParseCash(optarg);
1157             break;
1158
1159         case 'r': //credit
1160             conf.credit = ParseCredit(optarg);
1161             break;
1162
1163         case 'E': //credit expire
1164             conf.creditExpire = ParseCreditExpire(optarg);
1165             break;
1166
1167         case 'd': //down
1168             conf.disabled = ParseDownPassive(optarg);
1169             break;
1170
1171         case 'i': //passive
1172             conf.passive = ParseDownPassive(optarg);
1173             break;
1174
1175         case 't': //tariff
1176             ParseTariff(optarg, conf.tariffName, conf.nextTariff);
1177             break;
1178
1179         case 'm': //message
1180             ParseAnyString(optarg, &str);
1181             req.usrMsg = str;
1182             isMessage = true;
1183             break;
1184
1185         case 'e': //Prepaid Traffic
1186             stat.freeMb = ParsePrepaidTraffic(optarg);
1187             break;
1188
1189         case 'n': //Create User
1190             req.createUser = true;
1191             break;
1192
1193         case 'l': //Delete User
1194             req.deleteUser = true;
1195             break;
1196
1197         case 'N': //Note
1198             ParseAnyString(optarg, &str, "koi8-ru");
1199             conf.note = str;
1200             break;
1201
1202         case 'A': //nAme
1203             ParseAnyString(optarg, &str, "koi8-ru");
1204             conf.realName = str;
1205             break;
1206
1207         case 'D': //aDdress
1208             ParseAnyString(optarg, &str, "koi8-ru");
1209             conf.address = str;
1210             break;
1211
1212         case 'L': //emaiL
1213             ParseAnyString(optarg, &str, "koi8-ru");
1214             conf.email = str;
1215             break;
1216
1217         case 'P': //phone
1218             ParseAnyString(optarg, &str);
1219             conf.phone = str;
1220             break;
1221
1222         case 'G': //Group
1223             ParseAnyString(optarg, &str, "koi8-ru");
1224             conf.group = str;
1225             break;
1226
1227         case 'I': //IP-address of user
1228             ParseAnyString(optarg, &str);
1229             conf.ips = StrToIPS(str);
1230             break;
1231
1232         case 'S':
1233             conf.disabledDetailStat = ParseDownPassive(optarg);
1234             break;
1235
1236         case 'O':
1237             conf.alwaysOnline = ParseDownPassive(optarg);
1238             break;
1239
1240         case 500: //U
1241             SetArrayItem(stat.sessionUp, optarg, ParseTraff(argv[optind++]));
1242             break;
1243         case 501:
1244             SetArrayItem(stat.sessionDown, optarg, ParseTraff(argv[optind++]));
1245             break;
1246         case 502:
1247             SetArrayItem(stat.monthUp, optarg, ParseTraff(argv[optind++]));
1248             break;
1249         case 503:
1250             SetArrayItem(stat.monthDown, optarg, ParseTraff(argv[optind++]));
1251             break;
1252
1253         case 700: //UserData
1254             ParseAnyString(argv[optind++], &str);
1255             SetArrayItem(conf.userdata, optarg, str);
1256             break;
1257
1258         case '?':
1259             missedOptionArg = true;
1260             break;
1261
1262         case ':':
1263             missedOptionArg = true;
1264             break;
1265
1266         default:
1267             printf("?? getopt returned character code 0%o ??\n", c);
1268         }
1269     }
1270
1271 if (optind < argc)
1272     {
1273     printf ("non-option ARGV-elements: ");
1274     while (optind < argc)
1275         printf ("%s ", argv[optind++]);
1276     UsageConf();
1277     exit(PARAMETER_PARSING_ERR_CODE);
1278     }
1279
1280 if (missedOptionArg || !CheckParametersSet(&req))
1281     {
1282     //printf("Parameter needed\n");
1283     UsageConf();
1284     exit(PARAMETER_PARSING_ERR_CODE);
1285     }
1286
1287 const int rLen = 20000;
1288 char rstr[rLen];
1289 memset(rstr, 0, rLen);
1290
1291 if (isMessage)
1292     return ProcessSendMessage(req.server.data(), req.port.data(), req.admLogin.data(), req.admPasswd.data(), req.login.data(), req.usrMsg.data());
1293
1294 return ProcessSetUser(req.server.data(), req.port.data(), req.admLogin.data(), req.admPasswd.data(), req.login.data(), conf, stat);
1295 }
1296 //-----------------------------------------------------------------------------
1297 int main(int argc, char **argv)
1298 {
1299 SGCONF::CONFIG config;
1300
1301 SGCONF::OPTION_BLOCKS blocks;
1302 blocks.Add("General options")
1303       .Add("c", "config", SGCONF::MakeParamAction(config.configFile, std::string("~/.config/stg/sgconf.conf"), "<config file>"), "override default config file")
1304       .Add("h", "help", SGCONF::MakeFunc0Action(bind0(Method1Adapt(&SGCONF::OPTION_BLOCKS::Help, blocks), 0)), "\t\tshow this help and exit")
1305       .Add("help-all", SGCONF::MakeFunc0Action(UsageAll), "\t\tshow full help and exit")
1306       .Add("v", "version", SGCONF::MakeFunc0Action(Version), "\t\tshow version information and exit");
1307 SGCONF::OPTION_BLOCK & block = blocks.Add("Connection options")
1308       .Add("s", "server", SGCONF::MakeParamAction(config.server, std::string("localhost"), "<address>"), "\t\thost to connect")
1309       .Add("p", "port", SGCONF::MakeParamAction(config.port, uint16_t(5555), "<port>"), "\t\tport to connect")
1310       .Add("u", "username", SGCONF::MakeParamAction(config.userName, std::string("admin"), "<username>"), "\tadministrative login")
1311       .Add("w", "userpass", SGCONF::MakeParamAction(config.userPass, "<password>"), "\tpassword for the administrative login")
1312       .Add("a", "address", SGCONF::MakeParamAction(config, "<connection string>"), "connection params as a single string in format: <login>:<password>@<host>:<port>");
1313 blocks.Add("Raw XML")
1314       .Add("r", "raw", SGCONF::MakeFunc1Action(), "\t\tmake raw XML request")
1315 /*blocks.Add("Admins management options")
1316       .Add("get-admins", SGCONF::MakeConfAction())
1317       .Add("get-admin", SGCONF::MakeConfAction())
1318       .Add("add-admin", SGCONF::MakeConfAction())
1319       .Add("del-admin", SGCONF::MakeConfAction())
1320       .Add("chg-admin", SGCONF::MakeConfAction());*/
1321
1322
1323 SGCONF::PARSER_STATE state(false, argc, argv);
1324
1325 try
1326 {
1327 state = blocks.Parse(--argc, ++argv); // Skipping self name
1328 }
1329 catch (const SGCONF::OPTION::ERROR& ex)
1330 {
1331 std::cerr << ex.what() << "\n";
1332 return -1;
1333 }
1334
1335 if (state.stop)
1336     return 0;
1337
1338 if (state.argc > 0)
1339     {
1340     std::cerr << "Unknown option: '" << *state.argv << "'\n";
1341     return -1;
1342     }
1343
1344 try
1345 {
1346 SGCONF::CONFIG configOverride(config);
1347
1348 if (config.configFile.empty())
1349     {
1350     const char * mainConfigFile = "/etc/sgconf/sgconf.conf";
1351     if (access(mainConfigFile, R_OK) == 0)
1352         block.ParseFile(mainConfigFile);
1353     ReadUserConfigFile(block);
1354     }
1355 else
1356     {
1357     block.ParseFile(config.configFile.data());
1358     }
1359
1360 config = configOverride;
1361 }
1362 catch (const std::exception& ex)
1363 {
1364 std::cerr << ex.what() << "\n";
1365 return -1;
1366 }
1367
1368 std::cerr << "Config: " << config.Serialize() << std::endl;
1369
1370 return 0;
1371
1372 if (argc < 2)
1373     {
1374     Usage();
1375     return 1;
1376     }
1377
1378 if (argc <= 2)
1379     {
1380     UsageConf();
1381     exit(PARAMETER_PARSING_ERR_CODE);
1382     }
1383
1384 if (strcmp(argv[1], "get") == 0)
1385     {
1386     //printf("get\n");
1387     return mainGet(argc - 1, argv + 1);
1388     }
1389 else if (strcmp(argv[1], "set") == 0)
1390     {
1391     //printf("set\n");
1392     if (mainSet(argc - 1, argv + 1) )
1393         return 0;
1394     return -1;
1395     }
1396 else
1397     {
1398     UsageConf();
1399     exit(PARAMETER_PARSING_ERR_CODE);
1400     }
1401 return UNKNOWN_ERR_CODE;
1402 }
1403 //-----------------------------------------------------------------------------
1404
1405 namespace
1406 {
1407
1408 void Usage()
1409 {
1410 UsageImpl(false);
1411 }
1412
1413 void UsageAll()
1414 {
1415 UsageImpl(true);
1416 }
1417
1418 void UsageImpl(bool full)
1419 {
1420 std::cout << "sgconf is the Stargazer management utility.\n\n"
1421           << "Usage:\n"
1422           << "\tsgconf [options]\n\n"
1423           << "General options:\n"
1424           << "\t-c, --config <config file>\t\toverride default config file (default: \"~/.config/stg/sgconf.conf\")\n"
1425           << "\t-h, --help\t\t\t\tshow this help and exit\n"
1426           << "\t--help-all\t\t\t\tshow full help and exit\n"
1427           << "\t-v, --version\t\t\t\tshow version information and exit\n\n";
1428 UsageConnection();
1429 UsageAdmins(full);
1430 UsageTariffs(full);
1431 UsageUsers(full);
1432 UsageServices(full);
1433 UsageCorporations(full);
1434 }
1435 //-----------------------------------------------------------------------------
1436 void UsageConnection()
1437 {
1438 std::cout << "Connection options:\n"
1439           << "\t-s, --server <address>\t\t\thost to connect (ip or domain name, default: \"localhost\")\n"
1440           << "\t-p, --port <port>\t\t\tport to connect (default: \"5555\")\n"
1441           << "\t-u, --username <username>\t\tadministrative login (default: \"admin\")\n"
1442           << "\t-w, --userpass <password>\t\tpassword for administrative login\n"
1443           << "\t-a, --address <connection string>\tconnection params as a single string in format: <login>:<password>@<host>:<port>\n\n";
1444 }
1445 //-----------------------------------------------------------------------------
1446 void UsageAdmins(bool full)
1447 {
1448 std::cout << "Admins management options:\n"
1449           << "\t--get-admins\t\t\t\tget a list of admins (subsequent options will define what to show)\n";
1450 if (full)
1451     std::cout << "\t\t--login\t\t\t\tshow admin's login\n"
1452               << "\t\t--priv\t\t\t\tshow admin's priviledges\n\n";
1453 std::cout << "\t--get-admin\t\t\t\tget the information about admin\n";
1454 if (full)
1455     std::cout << "\t\t--login <login>\t\t\tlogin of the admin to show\n"
1456               << "\t\t--priv\t\t\t\tshow admin's priviledges\n\n";
1457 std::cout << "\t--add-admin\t\t\t\tadd a new admin\n";
1458 if (full)
1459     std::cout << "\t\t--login <login>\t\t\tlogin of the admin to add\n"
1460               << "\t\t--password <password>\t\tpassword of the admin to add\n"
1461               << "\t\t--priv <priv number>\t\tpriviledges of the admin to add\n\n";
1462 std::cout << "\t--del-admin\t\t\t\tdelete an existing admin\n";
1463 if (full)
1464     std::cout << "\t\t--login <login>\t\t\tlogin of the admin to delete\n\n";
1465 std::cout << "\t--chg-admin\t\t\t\tchange an existing admin\n";
1466 if (full)
1467     std::cout << "\t\t--login <login>\t\t\tlogin of the admin to change\n"
1468               << "\t\t--priv <priv number>\t\tnew priviledges\n\n";
1469 }
1470 //-----------------------------------------------------------------------------
1471 void UsageTariffs(bool full)
1472 {
1473 std::cout << "Tariffs management options:\n"
1474           << "\t--get-tariffs\t\t\t\tget a list of tariffs (subsequent options will define what to show)\n";
1475 if (full)
1476     std::cout << "\t\t--name\t\t\t\tshow tariff's name\n"
1477               << "\t\t--fee\t\t\t\tshow tariff's fee\n"
1478               << "\t\t--free\t\t\t\tshow tariff's prepaid traffic in terms of cost\n"
1479               << "\t\t--passive-cost\t\t\tshow tariff's cost of \"freeze\"\n"
1480               << "\t\t--traff-type\t\t\tshow what type of traffix will be accounted by the tariff\n"
1481               << "\t\t--dirs\t\t\t\tshow tarification rules for directions\n\n";
1482 std::cout << "\t--get-tariff\t\t\t\tget the information about tariff\n";
1483 if (full)
1484     std::cout << "\t\t--name <name>\t\t\tname of the tariff to show\n"
1485               << "\t\t--fee\t\t\t\tshow tariff's fee\n"
1486               << "\t\t--free\t\t\t\tshow tariff's prepaid traffic in terms of cost\n"
1487               << "\t\t--passive-cost\t\t\tshow tariff's cost of \"freeze\"\n"
1488               << "\t\t--traff-type\t\t\tshow what type of traffix will be accounted by the tariff\n"
1489               << "\t\t--dirs\t\t\t\tshow tarification rules for directions\n\n";
1490 std::cout << "\t--add-tariff\t\t\t\tadd a new tariff\n";
1491 if (full)
1492     std::cout << "\t\t--name <name>\t\t\tname of the tariff to add\n"
1493               << "\t\t--fee <fee>\t\t\tstariff's fee\n"
1494               << "\t\t--free <free>\t\t\ttariff's prepaid traffic in terms of cost\n"
1495               << "\t\t--passive-cost <cost>\t\ttariff's cost of \"freeze\"\n"
1496               << "\t\t--traff-type <type>\t\twhat type of traffi will be accounted by the tariff\n"
1497               << "\t\t--times <times>\t\t\tslash-separated list of \"day\" time-spans (in form \"hh:mm-hh:mm\") for each direction\n"
1498               << "\t\t--prices-day-a <prices>\t\tslash-separated list of prices for \"day\" traffic before threshold for each direction\n"
1499               << "\t\t--prices-night-a <prices>\tslash-separated list of prices for \"night\" traffic before threshold for each direction\n"
1500               << "\t\t--prices-day-b <prices>\t\tslash-separated list of prices for \"day\" traffic after threshold for each direction\n"
1501               << "\t\t--prices-night-b <prices>\tslash-separated list of prices for \"night\" traffic after threshold for each direction\n"
1502               << "\t\t--single-prices <yes|no>\tslash-separated list of \"single price\" flags for each direction\n"
1503               << "\t\t--no-discounts <yes|no>\t\tslash-separated list of \"no discount\" flags for each direction\n"
1504               << "\t\t--thresholds <thresholds>\tslash-separated list of thresholds (in Mb) for each direction\n\n";
1505 std::cout << "\t--del-tariff\t\t\t\tdelete an existing tariff\n";
1506 if (full)
1507     std::cout << "\t\t--name <name>\t\t\tname of the tariff to delete\n\n";
1508 std::cout << "\t--chg-tariff\t\t\t\tchange an existing tariff\n";
1509 if (full)
1510     std::cout << "\t\t--name <name>\t\t\tname of the tariff to change\n"
1511               << "\t\t--fee <fee>\t\t\tstariff's fee\n"
1512               << "\t\t--free <free>\t\t\ttariff's prepaid traffic in terms of cost\n"
1513               << "\t\t--passive-cost <cost>\t\ttariff's cost of \"freeze\"\n"
1514               << "\t\t--traff-type <type>\t\twhat type of traffix will be accounted by the tariff\n"
1515               << "\t\t--dir <N>\t\t\tnumber of direction data to change\n"
1516               << "\t\t\t--time <time>\t\t\"day\" time-span (in form \"hh:mm-hh:mm\")\n"
1517               << "\t\t\t--price-day-a <price>\tprice for \"day\" traffic before threshold\n"
1518               << "\t\t\t--price-night-a <price>\tprice for \"night\" traffic before threshold\n"
1519               << "\t\t\t--price-day-b <price>\tprice for \"day\" traffic after threshold\n"
1520               << "\t\t\t--price-night-b <price>\tprice for \"night\" traffic after threshold\n"
1521               << "\t\t\t--single-price <yes|no>\t\"single price\" flag\n"
1522               << "\t\t\t--no-discount <yes|no>\t\"no discount\" flag\n"
1523               << "\t\t\t--threshold <threshold>\tthreshold (in Mb)\n\n";
1524 }
1525 //-----------------------------------------------------------------------------
1526 void UsageUsers(bool full)
1527 {
1528 std::cout << "Users management options:\n"
1529           << "\t--get-users\t\t\t\tget a list of users (subsequent options will define what to show)\n";
1530 if (full)
1531     std::cout << "\n\n";
1532 std::cout << "\t--get-user\t\t\t\tget the information about user\n";
1533 if (full)
1534     std::cout << "\n\n";
1535 std::cout << "\t--add-user\t\t\t\tadd a new user\n";
1536 if (full)
1537     std::cout << "\n\n";
1538 std::cout << "\t--del-user\t\t\t\tdelete an existing user\n";
1539 if (full)
1540     std::cout << "\n\n";
1541 std::cout << "\t--chg-user\t\t\t\tchange an existing user\n";
1542 if (full)
1543     std::cout << "\n\n";
1544 std::cout << "\t--check-user\t\t\t\tcheck credentials is valid\n";
1545 if (full)
1546     std::cout << "\n\n";
1547 std::cout << "\t--send-message\t\t\t\tsend a message to a user\n";
1548 if (full)
1549     std::cout << "\n\n";
1550 }
1551 //-----------------------------------------------------------------------------
1552 void UsageServices(bool full)
1553 {
1554 std::cout << "Services management options:\n"
1555           << "\t--get-services\t\t\t\tget a list of services (subsequent options will define what to show)\n";
1556 if (full)
1557     std::cout << "\t\t--name\t\t\t\tshow service's name\n"
1558               << "\t\t--comment\t\t\tshow a comment to the service\n"
1559               << "\t\t--cost\t\t\t\tshow service's cost\n"
1560               << "\t\t--pay-day\t\t\tshow service's pay day\n\n";
1561 std::cout << "\t--get-service\t\t\t\tget the information about service\n";
1562 if (full)
1563     std::cout << "\t\t--name <name>\t\t\tname of the service to show\n"
1564               << "\t\t--comment\t\t\tshow a comment to the service\n"
1565               << "\t\t--cost\t\t\t\tshow service's cost\n"
1566               << "\t\t--pay-day\t\t\tshow service's pay day\n\n";
1567 std::cout << "\t--add-service\t\t\t\tadd a new service\n";
1568 if (full)
1569     std::cout << "\t\t--name <name>\t\t\tname of the service to add\n"
1570               << "\t\t--comment <comment>\t\ta comment to the service\n"
1571               << "\t\t--cost <cost>\t\t\tservice's cost\n"
1572               << "\t\t--pay-day <day>\t\t\tservice's pay day\n\n";
1573 std::cout << "\t--del-service\t\t\t\tdelete an existing service\n";
1574 if (full)
1575     std::cout << "\t\t--name <name>\t\t\tname of the service to delete\n\n";
1576 std::cout << "\t--chg-service\t\t\t\tchange an existing service\n";
1577 if (full)
1578     std::cout << "\t\t--name <name>\t\t\tname of the service to change\n"
1579               << "\t\t--comment <comment>\t\ta comment to the service\n"
1580               << "\t\t--cost <cost>\t\t\tservice's cost\n"
1581               << "\t\t--pay-day <day>\t\t\tservice's pay day\n\n";
1582 }
1583 //-----------------------------------------------------------------------------
1584 void UsageCorporations(bool full)
1585 {
1586 std::cout << "Corporations management options:\n"
1587           << "\t--get-corporations\t\t\tget a list of corporations (subsequent options will define what to show)\n";
1588 if (full)
1589     std::cout << "\t\t--name\t\t\t\tshow corporation's name\n"
1590               << "\t\t--cash\t\t\t\tshow corporation's cash\n\n";
1591 std::cout << "\t--get-corp\t\t\t\tget the information about corporation\n";
1592 if (full)
1593     std::cout << "\t\t--name <name>\t\t\tname of the corporation to show\n"
1594               << "\t\t--cash\t\t\t\tshow corporation's cash\n\n";
1595 std::cout << "\t--add-corp\t\t\t\tadd a new corporation\n";
1596 if (full)
1597     std::cout << "\t\t--name <name>\t\t\tname of the corporation to add\n"
1598               << "\t\t--cash <cash>\t\t\tinitial corporation's cash (default: \"0\")\n\n";
1599 std::cout << "\t--del-corp\t\t\t\tdelete an existing corporation\n";
1600 if (full)
1601     std::cout << "\t\t--name <name>\t\t\tname of the corporation to delete\n\n";
1602 std::cout << "\t--chg-corp\t\t\t\tchange an existing corporation\n";
1603 if (full)
1604     std::cout << "\t\t--name <name>\t\t\tname of the corporation to change\n"
1605               << "\t\t--add-cash <amount>[:<message>]\tadd cash to the corporation's account and optional comment message\n"
1606               << "\t\t--set-cash <cash>[:<message>]\tnew corporation's cash and optional comment message\n\n";
1607 }
1608
1609 void Version()
1610 {
1611 std::cout << "sgconf, version: 2.0.0-alpha.\n";
1612 }
1613
1614 } // namespace anonymous