8 #include <boost/tokenizer.hpp> 10 #include <dbus/dbus-glib-lowlevel.h> 20 kStateDisconnected = 1,
45 const size_t p =
id.find_first_of(
'/');
49 return id.substr(1, p-1);
54 static DBusHandlerResult
NotifyHandler(DBusConnection *, DBusMessage *dbus_msg,
void *user_data)
56 static_cast<SkypeClient*
>(user_data)->HandleDBusMessage(dbus_msg);
58 return DBUS_HANDLER_RESULT_HANDLED;
64 return GetCurrentState();
66 for (
auto it=fContacts.begin(); it!=fContacts.end(); it++)
70 msg << evt.
GetString() <<
" [" << fContacts.size() <<
"]";
74 return GetCurrentState();
79 if (evt.
GetSize()==0 || !fAllowRaw)
80 return GetCurrentState();
84 return GetCurrentState();
90 for (
auto it=fContacts.begin(); it!=fContacts.end(); it++)
92 const string user = Contact(*it);
96 SendDBusMessageNB(
"CALL "+user);
102 msg <<
"CALLING [" << cnt <<
"/" << fContacts.size() <<
"]";
106 return GetCurrentState();
194 return GetCurrentState();
199 DBusMessage *send = GetDBusMessage(cmd);
204 dbus_error_init(&error);
210 dbus_connection_send_with_reply_and_block(fBus, send,
230 Error(
"dbus_connection_send_with_reply_and_block: "+
string(error.message));
231 dbus_error_free(&error);
237 dbus_message_get_args(reply, 0, DBUS_TYPE_STRING, &ack, DBUS_TYPE_INVALID);
240 Info(
"RX: "+
string(ack));
242 const string rc = ack;
246 dbus_message_unref(send);
247 dbus_message_unref(reply);
262 dbus_message_new_method_call(
"com.Skype.API",
"/com/Skype",
263 "com.Skype.API",
"Invoke");
266 Error(
"dbus_message_new_method_call failed.");
274 const char *msg = cmd.c_str();
275 dbus_message_append_args(send,
276 DBUS_TYPE_STRING, &msg,
284 DBusMessage *send = GetDBusMessage(
"MINIMIZE");
289 const bool rc = dbus_connection_send(fBus, send, NULL);
293 dbus_message_unref(send);
300 DBusMessage *send = GetDBusMessage(cmd);
306 const bool rc = dbus_connection_send(fBus, send, NULL);
310 dbus_message_unref(send);
317 return SendDBusMessageNB(
"CHATMESSAGE "+chat+
" "+msg);
335 vector<string>
Split(
const string &msg)
337 using namespace boost;
339 typedef char_separator<char> separator;
340 const tokenizer<separator> tok(msg, separator(
" "));
343 for (
auto it=tok.begin(); it!=tok.end(); it++)
344 vec.push_back((*it)[0]==0?it->substr(1):*it);
351 if (GetCurrentState()!=kStateConnected)
360 char *notify_argument=0;
361 dbus_message_get_args(dbus_msg, 0,
362 DBUS_TYPE_STRING, ¬ify_argument,
365 Info(
"Notify: "+
string(notify_argument));
367 const vector<string> vec =
Split(notify_argument);
369 if (vec[0]==
"CURRENTUSERHANDLE")
373 Error(
"Wrong user '"+vec[1]+
"' logged in, '"+fUser+
"' expected!");
374 fNewState = kStateDisconnected;
379 if (vec[0]==
"CONNSTATUS")
382 if (vec[1]!=
"ONLINE")
384 Error(
"Connection status '"+vec[1]+
"'");
385 fNewState = kStateDisconnected;
390 if (vec[0]==
"USERSTATUS")
392 if (vec[1]!=
"ONLINE")
394 Info(
"Skype user not visible... setting online.");
395 SendDBusMessageNB(
"SET USERSTATUS ONLINE");
403 if (vec[2]==
"ONLINESTATUS")
405 if (vec[3]==
"OFFLINE")
408 Info(
"User '"+vec[1]+
"' changed status to '"+vec[3]+
"'");
412 if (vec[2]==
"RECEIVEDAUTHREQUEST")
413 SendDBusMessageNB(
"SET USER "+vec[1]+
" BUDDYSTATUS 2 "+fAuthorizationMsg);
426 if (vec[0]==
"CHATMESSAGE")
428 if (vec[2]==
"STATUS" && (vec[3]==
"RECEIVED"|| vec[3]==
"READ"))
430 const uint64_t last = stoll(vec[1]);
434 if (last<=fLastReadMessage)
436 fLastReadMessage = last;
440 rc=SendDBusMessage(
"GET CHATMESSAGE "+vec[1]+
" CHATNAME");
442 const string id =
Split(rc)[3];
444 rc=SendDBusMessage(
"GET CHATMESSAGE "+vec[1]+
" BODY");
446 const size_t p = rc.find(
" BODY ");
449 cout<<
"BODY TAG NOT FOUND|" << rc <<
"|" << endl;
457 auto it = find(fContacts.begin(), fContacts.end(),
id);
458 if (it==fContacts.end())
460 SendSkypeMessage(
id,
"Successfully subscribed.");
461 fContacts.push_back(
id);
464 SendSkypeMessage(
id,
"You are already subscribed.");
470 auto it = find(fContacts.begin(), fContacts.end(),
id);
471 if (it!=fContacts.end())
473 SendSkypeMessage(
id,
"Successfully un-subscribed.");
477 SendSkypeMessage(
id,
"You were not subscribed.");
484 for (
auto it=fContacts.begin(); it!=fContacts.end(); it++)
488 SendSkypeMessage(
id,
"You are subscribed.");
492 SendSkypeMessage(
id,
"You are not subscribed.");
496 SendSkypeMessage(
id,
"SYNTAX ERROR\n\nAvailable commands:\nPlease use either 'start', 'stop' or 'status'");
503 const string id = vec[1];
504 if (vec[2]==
"ACTIVITY_TIMESTAMP")
510 if (vec[2]==
"MYROLE")
513 if (vec[2]==
"MEMBERS")
516 if (vec[2]==
"ACTIVEMEMBERS")
519 if (vec[2]==
"STATUS")
523 if (vec[2]==
"TIMESTAMP")
526 if (vec[2]==
"DIALOG_PARTNER")
529 if (vec[2]==
"FRIENDLYNAME")
537 if (vec[2]==
"STATUS" && vec[2]==
"INPROGRESS")
538 SendDBusMessageNB(
"SET CALL "+vec[1]+
"STATUS FINISHED");
549 return kStateDisconnected;
554 fLastConnect =
Time();
557 if (SendDBusMessage(
"NAME FACT++")!=
"OK")
558 return kStateDisconnected;
561 if (SendDBusMessage(
"PROTOCOL 5")!=
"PROTOCOL 5")
562 return kStateDisconnected;
565 SendDBusMessageNB(
"MINIMIZE");
568 SendDBusMessageNB(
"SET AUTOAWAY OFF");
571 const string rc = SendDBusMessage(
"SEARCH USERSWAITINGMYAUTHORIZATION");
574 vector<string> users =
Split(rc);
576 if (users[0]!=
"USERS")
578 Error(
"Unexpected answer received '"+rc+
"'");
579 return kStateDisconnected;
582 for (
auto it=users.begin()+1; it!=users.end(); it++)
584 const size_t p = it->length()-1;
588 SendDBusMessageNB(
"SET USER "+*it+
" BUDDYSTATUS 2 "+fAuthorizationMsg);
591 return kStateConnected;
601 static GMainContext *context = g_main_loop_get_context(fLoop);
602 g_main_context_iteration(context,
FALSE);
609 if (GetCurrentState()>kStateDisconnected)
611 if (now-fLastPing>boost::posix_time::seconds(15))
613 if (SendDBusMessage(
"PING",
false)!=
"PONG")
614 return kStateDisconnected;
619 return GetCurrentState();
622 if (now-fLastConnect>boost::posix_time::minutes(1))
623 return HandleConnect();
625 return GetCurrentState();
630 fLastConnect(
Time()-
boost::posix_time::minutes(5)), fLoop(0),
633 AddStateName(kStateDisconnected,
"Disonnected",
"");
634 AddStateName(kStateConnected,
"Connected",
"");
636 AddEvent(
"MSG",
"C", kStateConnected)
638 (
"|msg[string]:message to be distributed");
642 (
"|msg[string]:send a raw message to the Skype API");
644 AddEvent(
"CALL",
"", kStateConnected)
648 AddEvent(
"CONNECT", kStateDisconnected)
652 AddEvent(
"DISCONNECT", kStateConnected)
656 fLoop = g_main_loop_new(NULL,
FALSE);
660 g_main_loop_unref(fLoop);
665 fUser = conf.
Get<
string>(
"user");
666 fAllowRaw = conf.
Get<
bool>(
"allow-raw");
670 dbus_error_init(&error);
672 fBus = dbus_bus_get(DBUS_BUS_SESSION, &error);
675 Error(
"dbus_bus_get failed: "+
string(error.message));
676 dbus_error_free(&error);
681 dbus_connection_setup_with_g_main(fBus, NULL);
685 DBusObjectPathVTable vtable;
689 const dbus_bool_t check =
690 dbus_connection_register_object_path(fBus,
"/com/Skype/Client",
694 Error(
"dbus_connection_register_object_path failed.");
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.";
717 const string n = conf.
GetName()+
".log";
719 po::options_description config(
"Skype client 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)")
740 "The skypeclient is a Dim to Skype interface.\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" 747 "Usage: skypeclient [OPTIONS]\n" 748 " or: skypeclient [OPTIONS]\n";
761 int main(
int argc,
const char *argv[])
772 if (!conf.
Has(
"console"))
773 return Main::execute<LocalStream, SkypeClient>(conf);
775 if (conf.
Get<
int>(
"console")==0)
776 return Main::execute<LocalShell, SkypeClient>(conf);
778 return Main::execute<LocalConsole, SkypeClient>(conf);
A general base-class describing events issues in a state machine.
void HandleDBusMessage(DBusMessage *dbus_msg)
int HandleRaw(const EventImp &evt)
void SetupConfiguration(Configuration &conf)
int main(int argc, const char *argv[])
int EvalOptions(Configuration &conf)
Adds some functionality to boost::posix_time::ptime for our needs.
void SetPrintUsage(const std::function< void(void)> &func)
T Get(const std::string &var)
string SendDBusMessage(const string &cmd, bool display=true)
int Execute()
Is called continously to execute actions in the current state.
std::string GetString() const
int Write(const Time &time, const string &txt, int severity=MessageImp::kMessage)
uint64_t fLastReadMessage
DBusMessage * GetDBusMessage(const string &cmd)
Just a message, usually obsolete.
virtual int Write(const Time &time, const std::string &txt, int qos=kMessage)
bool Has(const std::string &var)
void SetupConfiguration(Configuration &conf)
vector< string > Split(const string &msg)
void AddOptions(const po::options_description &opt, bool visible=true)
string Contact(const string &id) const
Warning because the service this data corrsponds to might have been last updated longer ago than Local time
int HandleMsg(const EventImp &evt)
static const string fAuthorizationMsg
Commandline parsing, resource file parsing and database access.
Class for a state machine implementation within a DIM network.
bool SendDBusMessageNB(const string &cmd)
static DBusHandlerResult NotifyHandler(DBusConnection *, DBusMessage *dbus_msg, void *user_data)
po::typed_value< bool > * po_bool(bool def=false)
bool DoParse(int argc, const char **argv, const std::function< void()> &func=std::function< void()>())
const std::string & GetName() const
SkypeClient(ostream &lout)
int HandleSMS(const EventImp &)
bool SendSkypeMessage(const string &chat, const string &msg)
vector< string > fContacts
virtual size_t GetSize() const