source: trunk/FACT++/src/skypeclient.cc@ 20115

Last change on this file since 20115 was 14239, checked in by tbretz, 13 years ago
Replaced DBUS_TIMEOUT_USE_DEFAULT by -1, otherwise we need additional headers.
File size: 24.2 KB
Line 
1#include <iostream>
2
3#include "EventImp.h"
4#include "Configuration.h"
5#include "StateMachineDim.h"
6#include "LocalControl.h"
7
8#include <boost/tokenizer.hpp>
9
10#include <dbus/dbus-glib-lowlevel.h>
11
12using namespace std;
13
14class SkypeClient : public StateMachineDim
15{
16private:
17 static const string fAuthorizationMsg;
18
19 enum {
20 kStateDisconnected = 1,
21 kStateConnected = 2,
22 };
23
24 Time fLastConnect;
25
26 DBusConnection *fBus;
27 GMainLoop *fLoop;
28
29 vector<string> fContacts;
30
31 string fUser;
32
33 bool fAllowRaw;
34
35 uint64_t fLastReadMessage;
36
37 string Contact(const string &id) const
38 {
39 if (id.size()==0)
40 return "";
41
42 if (id[0]!='#')
43 return "";
44
45 const size_t p = id.find_first_of('/');
46 if (p==string::npos)
47 return "";
48
49 return id.substr(1, p-1);
50 }
51
52
53
54 static DBusHandlerResult NotifyHandler(DBusConnection *, DBusMessage *dbus_msg, void *user_data)
55 {
56 static_cast<SkypeClient*>(user_data)->HandleDBusMessage(dbus_msg);
57 static_cast<SkypeClient*>(user_data)->Minimize();
58 return DBUS_HANDLER_RESULT_HANDLED;
59 }
60
61 int HandleMsg(const EventImp &evt)
62 {
63 if (evt.GetSize()==0)
64 return GetCurrentState();
65
66 for (auto it=fContacts.begin(); it!=fContacts.end(); it++)
67 SendSkypeMessage(*it, evt.GetString());
68
69 ostringstream msg;
70 msg << evt.GetString() << " [" << fContacts.size() << "]";
71
72 Info(msg);
73
74 return GetCurrentState();
75 }
76
77 int HandleRaw(const EventImp &evt)
78 {
79 if (evt.GetSize()==0 || !fAllowRaw)
80 return GetCurrentState();
81
82 SendDBusMessage(evt.GetString());
83
84 return GetCurrentState();
85 }
86
87 int HandleCall()
88 {
89 int cnt = 0;
90 for (auto it=fContacts.begin(); it!=fContacts.end(); it++)
91 {
92 const string user = Contact(*it);
93 if (user.empty())
94 continue;
95
96 SendDBusMessageNB("CALL "+user);
97
98 cnt++;
99 }
100
101 ostringstream msg;
102 msg << "CALLING [" << cnt << "/" << fContacts.size() << "]";
103
104 Info(msg);
105
106 return GetCurrentState();
107 }
108
109 int HandleSMS(const EventImp &/*sms*/)
110 {
111 /*
112 -> CREATE SMS OUTGOING +0123456789
113 <- SMS 821 STATUS COMPOSING
114 <- SMS 821 PRICE 0
115 <- SMS 821 TIMESTAMP 0
116 <- SMS 821 PRICE_PRECISION 3
117 <- SMS 821 PRICE_CURRENCY EUR
118 <- SMS 821 STATUS COMPOSING
119 <- SMS 821 TARGET_NUMBERS +0123456789
120 <- SMS 821 PRICE -1
121 <- SMS 821 TARGET_STATUSES +0123456789=TARGET_ANALYZING
122 <- SMS 821 TARGET_STATUSES +0123456789=TARGET_ACCEPTABLE
123 <- SMS 821 PRICE 78
124
125 //-------------------------------------------------------------------
126 // Now let's add two more target numbers (in addition to original)
127 -> SET SMS 1702 TARGET_NUMBERS +37259877305, +37259877306, +37259877307
128 <- SMS 1702 TARGET_NUMBERS +37259877305, +37259877306, +37259877307
129 <- SMS 1702 TARGET_NUMBERS +37259877305, +37259877306, +37259877307
130 <- SMS 1702 PRICE -1
131 <- SMS 1702 TARGET_STATUSES +37259877305=TARGET_ACCEPTABLE, +37259877306=TARGET_ANALYZING, +37259877307=TARGET_ANALYZING
132 <- SMS 1702 TARGET_STATUSES +37259877305=TARGET_ACCEPTABLE, +37259877306=TARGET_ACCEPTABLE, +37259877307=TARGET_ACCEPTABLE
133 <- SMS 1702 TARGET_STATUSES +37259877305=TARGET_ACCEPTABLE, +37259877306=TARGET_ACCEPTABLE, +37259877307=TARGET_ACCEPTABLE
134 <- SMS 1702 PRICE 234
135
136 TARGET_ANALYZING
137 TARGET_UNDEFINED
138 TARGET_ACCEPTABLE
139 TARGET_NOT_ROUTABLE
140 TARGET_DELIVERY_PENDING
141 TARGET_DELIVERY_SUCCESSFUL
142 TARGET_DELIVERY_FAILED
143 UNKNOWN
144
145 // ----------------------------------------------------------------
146 // This is how to set the message text property
147 // Note that you will get two identical lines in response
148 -> SET SMS 821 BODY "test 123 test 223 test 333"
149 <- SMS 821 BODY "test 123 test 223 test 333"
150 <- SMS 821 BODY "test 123 test 223 test 333"
151
152 // ----------------------------------------------------------------
153 // Now lets try to send the message
154 -> ALTER SMS 821 SEND
155 <- ALTER SMS 821 SEND
156 <- SMS 821 STATUS SENDING_TO_SERVER
157 <- SMS 821 TIMESTAMP 1174058095
158 <- SMS 821 TARGET_STATUSES +0123456789=TARGET_ACCEPTABLE
159 <- SMS 821 TARGET_STATUSES +0123456789=TARGET_DELIVERY_FAILED
160 <- SMS 821 FAILUREREASON INSUFFICIENT_FUNDS
161 <- SMS 821 STATUS FAILED
162 <- SMS 821 IS_FAILED_UNSEEN TRUE
163
164 STATUS
165 RECEIVED the message has been received (but not tagged as read)
166 READ the message has been tagged as read
167 COMPOSING the message has been created but not yet sent
168 SENDING_TO_SERVER the message is in process of being sent to server
169 SENT_TO_SERVER the message has been sent to server
170 DELIVERED server has confirmed that the message is sent out to recepient
171 SOME_TARGETS_FAILED server reports failure to deliver the message to one of the recepients within 24h
172 FAILED the message has failed, possible reason may be found in FAILUREREASON property
173 UNKNOWN message status is unknown
174
175 FAILUREREASON
176 MISC_ERROR indicates failure to supply a meaningful error message
177 SERVER_CONNECT_FAILED unable to connect to SMS server
178 NO_SMS_CAPABILITY recepient is unable to receive SMS messages
179 INSUFFICIENT_FUNDS insufficient Skype Credit to send an SMS message
180 INVALID_CONFIRMATION_CODE set when an erroneous code was submitted in a CONFIRMATION_CODE_SUBMIT message
181 USER_BLOCKED user is blocked from the server
182 IP_BLOCKED user IP is blocked from the server
183 NODE_BLOCKED user p2p network node has been blocked from the server
184 UNKNOWN default failure code
185 NO_SENDERID_CAPABILITY Set when a CONFIRMATION_CODE_REQUEST SMS message is sent with a mobile phone number containing country code of either USA, Taiwan or China. Setting reply-to number from Skype SMS’s to your mobile number is not supported in these countries. Added in Skype version 3.5 (protocol 8).
186
187 // ----------------------------------------------------------------
188 // As sending the message failed (not enough Skype credit),
189 // lets delete the message
190 -> DELETE SMS 821
191 <- DELETE SMS 821
192 */
193
194 return GetCurrentState();
195 }
196
197 string SendDBusMessage(const string &cmd, bool display=true)
198 {
199 DBusMessage *send = GetDBusMessage(cmd);
200 if (!send)
201 return "";
202
203 DBusError error;
204 dbus_error_init(&error);
205
206 // Send the message and wait for reply
207 if (display)
208 Info("TX: "+cmd);
209 DBusMessage *reply=
210 dbus_connection_send_with_reply_and_block(fBus, send,
211 -1,//DBUS_TIMEOUT_USE_DEFAULT,
212 &error);
213 /*
214 DBusPendingCall *pending = 0;
215 if (!dbus_connection_send_with_reply (fBus, send,
216 &pending, DBUS_TIMEOUT_USE_DEFAULT))
217 return "";
218
219 if (!pending)
220 return "";
221
222 bool = dbus_pending_call_get_completed(pending);
223 //dbus_pending_call_block(pending);
224 DBusMessage *reply = dbus_pending_call_steal_reply(pending);
225 dbus_pending_call_unref(pending);
226 */
227
228 if (!reply)
229 {
230 Error("dbus_connection_send_with_reply_and_block: "+string(error.message));
231 dbus_error_free(&error);
232 return "";
233 }
234
235 // Get Skype's reply string
236 const char *ack = 0;
237 dbus_message_get_args(reply, 0, DBUS_TYPE_STRING, &ack, DBUS_TYPE_INVALID);
238
239 if (display)
240 Info("RX: "+string(ack));
241
242 const string rc = ack;
243
244 // Show no interest in the previously created messages.
245 // DBus will delete a message if reference count drops to zero.
246 dbus_message_unref(send);
247 dbus_message_unref(reply);
248
249 return rc;
250 }
251
252 DBusMessage *GetDBusMessage(const string &cmd)
253 {
254 // Create a message to be sent to Skype
255
256 // Constructs a new message to invoke a method on a remote object.
257 // Sets the service the message should be sent to "com.Skype.API"
258 // Sets the object path the message should be sent to "/com/Skype"
259 // Sets the interface to invoke method on to "com.Skype.API"
260 // Sets the method to invoke to "Invoke"
261 DBusMessage *send=
262 dbus_message_new_method_call("com.Skype.API", "/com/Skype",
263 "com.Skype.API", "Invoke");
264 if (!send)
265 {
266 Error("dbus_message_new_method_call failed.");
267 return NULL;
268 }
269
270 // Set the argument of the Invoke method
271 // Sets arg to be an argument to be passed to the Invoke method.
272 // It is an input argument. It has a type string.
273 // There are no output arguments.
274 const char *msg = cmd.c_str();
275 dbus_message_append_args(send,
276 DBUS_TYPE_STRING, &msg,
277 DBUS_TYPE_INVALID);
278
279 return send;
280 }
281
282 bool Minimize()
283 {
284 DBusMessage *send = GetDBusMessage("MINIMIZE");
285 if (!send)
286 return false;
287
288 // Send the message and ignore the reply
289 const bool rc = dbus_connection_send(fBus, send, NULL);
290
291 // Show no interest in the previously created messages.
292 // DBus will delete a message if reference count drops to zero.
293 dbus_message_unref(send);
294
295 return rc;
296 }
297
298 bool SendDBusMessageNB(const string &cmd)
299 {
300 DBusMessage *send = GetDBusMessage(cmd);
301 if (!send)
302 return false;
303
304 // Send the message and ignore the reply
305 Info("TX: "+cmd);
306 const bool rc = dbus_connection_send(fBus, send, NULL);
307
308 // Show no interest in the previously created messages.
309 // DBus will delete a message if reference count drops to zero.
310 dbus_message_unref(send);
311
312 return rc;
313 }
314
315 bool SendSkypeMessage(const string &chat, const string &msg)
316 {
317 return SendDBusMessageNB("CHATMESSAGE "+chat+" "+msg);
318/*
319 // SendDBusMessage(bus, "CHAT CREATE "+user);
320
321 const string rc = SendDBusMessage("CHATMESSAGE "+chat+" "+msg);
322
323 const vector<string> vec = Split(rc);
324 if (vec[0]=="ERROR")
325 {
326 auto it = find(fContacts.begin(), fContacts.end(), chat);
327 if (it!=fContacts.end())
328 fContacts.erase(it);
329 return false;
330 }
331
332 return true;
333 */
334 }
335 vector<string> Split(const string &msg)
336 {
337 using namespace boost;
338
339 typedef char_separator<char> separator;
340 const tokenizer<separator> tok(msg, separator(" "));
341
342 vector<string> vec;
343 for (auto it=tok.begin(); it!=tok.end(); it++)
344 vec.push_back((*it)[0]==0?it->substr(1):*it);
345
346 return vec;
347 }
348
349 void HandleDBusMessage(DBusMessage *dbus_msg)
350 {
351 if (GetCurrentState()!=kStateConnected)
352 return;
353
354 // CALL target1, target2, target3
355 // SET CALL <id> STATUS FINISHED
356
357 // Stores the argument passed to the Notify method
358 // into notify_argument.
359
360 char *notify_argument=0;
361 dbus_message_get_args(dbus_msg, 0,
362 DBUS_TYPE_STRING, &notify_argument,
363 DBUS_TYPE_INVALID);
364
365 Info("Notify: "+string(notify_argument));
366
367 const vector<string> vec = Split(notify_argument);
368
369 if (vec[0]=="CURRENTUSERHANDLE")
370 {
371 if (vec[1]!=fUser)
372 {
373 Error("Wrong user '"+vec[1]+"' logged in, '"+fUser+"' expected!");
374 fNewState = kStateDisconnected;
375 return;
376 }
377 }
378
379 if (vec[0]=="CONNSTATUS")
380 {
381 // OFFLINE / CONNECTING / PAUSING / ONLINE
382 if (vec[1]!="ONLINE")
383 {
384 Error("Connection status '"+vec[1]+"'");
385 fNewState = kStateDisconnected;
386 return;
387 }
388 }
389
390 if (vec[0]=="USERSTATUS")
391 {
392 if (vec[1]!="ONLINE")
393 {
394 Info("Skype user not visible... setting online.");
395 SendDBusMessageNB("SET USERSTATUS ONLINE");
396 }
397 }
398
399 // USER rtlprmft RECEIVEDAUTHREQUEST Please allow me to see when you are online
400
401 if (vec[0]=="USER")
402 {
403 if (vec[2]=="ONLINESTATUS")
404 {
405 if (vec[3]=="OFFLINE")
406 {
407 }
408 Info("User '"+vec[1]+"' changed status to '"+vec[3]+"'");
409 }
410
411 // Answer authorization requests
412 if (vec[2]=="RECEIVEDAUTHREQUEST")
413 SendDBusMessageNB("SET USER "+vec[1]+" BUDDYSTATUS 2 "+fAuthorizationMsg);
414
415 //if (vec[2]=="NROF_AUTHED_BUDDIES")
416 // cout << vec[1] << " --> " << vec[3];
417 }
418
419 if (vec[0]=="GROUP")
420 {
421 // 1: gorup id
422 // 2: NROFUSERS
423 // 3: n
424 }
425
426 if (vec[0]=="CHATMESSAGE")
427 {
428 if (vec[2]=="STATUS" && (vec[3]=="RECEIVED"|| vec[3]=="READ"))
429 {
430 const uint64_t last = stoll(vec[1]);
431
432 // Check if message has already been processed: Sometimes
433 // some messages are received twice as READ/READ
434 if (last<=fLastReadMessage)
435 return;
436 fLastReadMessage = last;
437
438 string rc;
439
440 rc=SendDBusMessage("GET CHATMESSAGE "+vec[1]+" CHATNAME");
441
442 const string id = Split(rc)[3];
443
444 rc=SendDBusMessage("GET CHATMESSAGE "+vec[1]+" BODY");
445
446 const size_t p = rc.find(" BODY ");
447 if (p==string::npos)
448 {
449 cout<< "BODY TAG NOT FOUND|" << rc << "|" << endl;
450 return;
451 }
452
453 rc = Tools::Trim(rc.substr(rc.find(" BODY ")+6));
454
455 if (rc=="start")
456 {
457 auto it = find(fContacts.begin(), fContacts.end(), id);
458 if (it==fContacts.end())
459 {
460 SendSkypeMessage(id, "Successfully subscribed.");
461 fContacts.push_back(id);
462 }
463 else
464 SendSkypeMessage(id, "You are already subscribed.");
465
466 return;
467 }
468 if (rc=="stop")
469 {
470 auto it = find(fContacts.begin(), fContacts.end(), id);
471 if (it!=fContacts.end())
472 {
473 SendSkypeMessage(id, "Successfully un-subscribed.");
474 fContacts.erase(it);
475 }
476 else
477 SendSkypeMessage(id, "You were not subscribed.");
478
479 return;
480 }
481
482 if (rc=="status")
483 {
484 for (auto it=fContacts.begin(); it!=fContacts.end(); it++)
485 {
486 if (*it==vec[1])
487 {
488 SendSkypeMessage(id, "You are subscribed.");
489 return;
490 }
491 }
492 SendSkypeMessage(id, "You are not subscribed.");
493 return;
494 }
495
496 SendSkypeMessage(id, "SYNTAX ERROR\n\nAvailable commands:\nPlease use either 'start', 'stop' or 'status'");
497
498 }
499 }
500
501 if (vec[0]=="CHAT")
502 {
503 const string id = vec[1];
504 if (vec[2]=="ACTIVITY_TIMESTAMP")
505 {
506 //SendDBusMessage("CHAT CREATE "+Contact(vec[1]));
507 //Info(vec[2]);
508 // ALTER CHAT DISBAND
509 }
510 if (vec[2]=="MYROLE")
511 {
512 }
513 if (vec[2]=="MEMBERS")
514 {
515 }
516 if (vec[2]=="ACTIVEMEMBERS")
517 {
518 }
519 if (vec[2]=="STATUS")
520 {
521 // vec[3]=="DIALOG")
522 }
523 if (vec[2]=="TIMESTAMP")
524 {
525 }
526 if (vec[2]=="DIALOG_PARTNER")
527 {
528 }
529 if (vec[2]=="FRIENDLYNAME")
530 {
531 // Notify: CHAT #maggiyy/$rtlprmft;da26ea52b3e70e65 FRIENDLYNAME Lamouette | noch ne message
532 }
533 }
534
535 if (vec[0]=="CALL")
536 {
537 if (vec[2]=="STATUS" && vec[2]=="INPROGRESS")
538 SendDBusMessageNB("SET CALL "+vec[1]+ "STATUS FINISHED");
539
540 // CALL 1501 STATUS UNPLACED
541 // CALL 1501 STATUS ROUTING
542 // CALL 1501 STATUS RINGING
543 }
544
545 }
546
547 int HandleDisconnect()
548 {
549 return kStateDisconnected;
550 }
551
552 int HandleConnect()
553 {
554 fLastConnect = Time();
555
556 // Enable client connection to Skype
557 if (SendDBusMessage("NAME FACT++")!="OK")
558 return kStateDisconnected;
559
560 // Negotiate protocol version
561 if (SendDBusMessage("PROTOCOL 5")!="PROTOCOL 5")
562 return kStateDisconnected;
563
564 // Now we are connected: Minimize the window...
565 SendDBusMessageNB("MINIMIZE");
566
567 // ... and switch off the away message
568 SendDBusMessageNB("SET AUTOAWAY OFF");
569
570 // Check for unauthorized users and...
571 const string rc = SendDBusMessage("SEARCH USERSWAITINGMYAUTHORIZATION");
572
573 // ...authorize them
574 vector<string> users = Split(rc);
575
576 if (users[0]!="USERS")
577 {
578 Error("Unexpected answer received '"+rc+"'");
579 return kStateDisconnected;
580 }
581
582 for (auto it=users.begin()+1; it!=users.end(); it++)
583 {
584 const size_t p = it->length()-1;
585 if (it->at(p)==',')
586 it->erase(p);
587
588 SendDBusMessageNB("SET USER "+*it+" BUDDYSTATUS 2 "+fAuthorizationMsg);
589 }
590
591 return kStateConnected;
592 }
593
594 Time fLastPing;
595 int fNewState;
596
597 int Execute()
598 {
599 fNewState = -1;
600
601 static GMainContext *context = g_main_loop_get_context(fLoop);
602 g_main_context_iteration(context, FALSE);
603
604 if (fNewState>0)
605 return fNewState;
606
607 const Time now;
608
609 if (GetCurrentState()>kStateDisconnected)
610 {
611 if (now-fLastPing>boost::posix_time::seconds(15))
612 {
613 if (SendDBusMessage("PING", false)!="PONG")
614 return kStateDisconnected;
615
616 fLastPing = now;
617 }
618
619 return GetCurrentState();
620 }
621
622 if (now-fLastConnect>boost::posix_time::minutes(1))
623 return HandleConnect();
624
625 return GetCurrentState();
626 }
627
628public:
629 SkypeClient(ostream &lout) : StateMachineDim(lout, "SKYPE"),
630 fLastConnect(Time()-boost::posix_time::minutes(5)), fLoop(0),
631 fLastReadMessage(0)
632 {
633 AddStateName(kStateDisconnected, "Disonnected", "");
634 AddStateName(kStateConnected, "Connected", "");
635
636 AddEvent("MSG", "C", kStateConnected)
637 (bind(&SkypeClient::HandleMsg, this, placeholders::_1))
638 ("|msg[string]:message to be distributed");
639
640 AddEvent("RAW", "C")
641 (bind(&SkypeClient::HandleRaw, this, placeholders::_1))
642 ("|msg[string]:send a raw message to the Skype API");
643
644 AddEvent("CALL", "", kStateConnected)
645 (bind(&SkypeClient::HandleCall, this))
646 ("");
647
648 AddEvent("CONNECT", kStateDisconnected)
649 (bind(&SkypeClient::HandleConnect, this))
650 ("");
651
652 AddEvent("DISCONNECT", kStateConnected)
653 (bind(&SkypeClient::HandleDisconnect, this))
654 ("");
655
656 fLoop = g_main_loop_new(NULL, FALSE);
657 }
658 ~SkypeClient()
659 {
660 g_main_loop_unref(fLoop);
661 }
662
663 int EvalOptions(Configuration &conf)
664 {
665 fUser = conf.Get<string>("user");
666 fAllowRaw = conf.Get<bool>("allow-raw");
667
668 // Get a connection to the session bus.
669 DBusError error;
670 dbus_error_init(&error);
671
672 fBus = dbus_bus_get(DBUS_BUS_SESSION, &error);
673 if (!fBus)
674 {
675 Error("dbus_bus_get failed: "+string(error.message));
676 dbus_error_free(&error);
677 return 1;
678 }
679
680 // Set up this connection to work in a GLib event loop.
681 dbus_connection_setup_with_g_main(fBus, NULL);
682
683 // Install notify handler to process Skype's notifications.
684 // The Skype-to-client method call.
685 DBusObjectPathVTable vtable;
686 vtable.message_function = SkypeClient::NotifyHandler;
687
688 // We will process messages with the object path "/com/Skype/Client".
689 const dbus_bool_t check =
690 dbus_connection_register_object_path(fBus, "/com/Skype/Client",
691 &vtable, this);
692 if (!check)
693 {
694 Error("dbus_connection_register_object_path failed.");
695 return 2;
696 }
697
698 return -1;
699 }
700
701 int Write(const Time &time, const string &txt, int severity=MessageImp::kMessage)
702 {
703 return MessageImp::Write(time, txt, severity);
704 }
705};
706
707const string SkypeClient::fAuthorizationMsg =
708 "This is an automatic client of the FACT project (www.fact-project.org). "
709 "If you haven't tried to get in contact with this bot, feel free to block it. "
710 "In case of problems or questions please contact system@fact-project.org.";
711
712
713// -------------------------------------------------------------------------------------
714
715void SetupConfiguration(Configuration &conf)
716{
717 const string n = conf.GetName()+".log";
718
719 po::options_description config("Skype client options");
720 config.add_options()
721 ("user", var<string>("www.fact-project.org"), "If a user is given only connection to a skype with this user are accepted.")
722 ("allow-raw", po_bool(false), "This allows sending raw messages to the SKype API (for debugging)")
723 ;
724
725 conf.AddOptions(config);
726}
727
728/*
729 Extract usage clause(s) [if any] for SYNOPSIS.
730 Translators: "Usage" and "or" here are patterns (regular expressions) which
731 are used to match the usage synopsis in program output. An example from cp
732 (GNU coreutils) which contains both strings:
733 Usage: cp [OPTION]... [-T] SOURCE DEST
734 or: cp [OPTION]... SOURCE... DIRECTORY
735 or: cp [OPTION]... -t DIRECTORY SOURCE...
736 */
737void PrintUsage()
738{
739 cout <<
740 "The skypeclient is a Dim to Skype interface.\n"
741 "\n"
742 "The default is that the program is started without user intercation. "
743 "All actions are supposed to arrive as DimCommands. Using the -c "
744 "option, a local shell can be initialized. With h or help a short "
745 "help message about the usuage can be brought to the screen.\n"
746 "\n"
747 "Usage: skypeclient [OPTIONS]\n"
748 " or: skypeclient [OPTIONS]\n";
749 cout << endl;
750}
751
752void PrintHelp()
753{
754 /* Additional help text which is printed after the configuration
755 options goes here */
756}
757
758
759#include "Main.h"
760
761int main(int argc, const char *argv[])
762{
763 Configuration conf(argv[0]);
764 conf.SetPrintUsage(PrintUsage);
765 Main::SetupConfiguration(conf);
766 SetupConfiguration(conf);
767
768 if (!conf.DoParse(argc, argv, PrintHelp))
769 return 127;
770
771 // No console access at all
772 if (!conf.Has("console"))
773 return Main::execute<LocalStream, SkypeClient>(conf);
774
775 if (conf.Get<int>("console")==0)
776 return Main::execute<LocalShell, SkypeClient>(conf);
777 else
778 return Main::execute<LocalConsole, SkypeClient>(conf);
779
780 return 0;
781}
Note: See TracBrowser for help on using the repository browser.