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