bool findObject(const char *app, const char *obj, const char *func, KStringList args) { QString f = func; // Qt is better with unicode strings, so use one. int left = f.find('('); int right = f.find(')'); if(right < left) { qWarning("parentheses do not match"); exit(1); } if(!f.isEmpty() && (left < 0)) f += "()"; // This may seem expensive but is done only once per invocation // of dcop, so it should be OK. // // QStringList intTypes; intTypes << "int" << "unsigned" << "long" << "bool"; QStringList types; if(left > 0 && left + 1 < right - 1) { types = QStringList::split(',', f.mid(left + 1, right - left - 1)); for(QStringList::Iterator it = types.begin(); it != types.end(); ++it) { QString lt = (*it).simplifyWhiteSpace(); int s = lt.find(' '); // If there are spaces in the name, there may be two // reasons: the parameter name is still there, ie. // "QString URL" or it's a complicated int type, ie. // "unsigned long long int bool". // // if(s > 0) { QStringList partl = QStringList::split(' ', lt); // The zero'th part is -- at the very least -- a // type part. Any trailing parts *might* be extra // int-type keywords, or at most one may be the // parameter name. // // s = 1; while(s < (int)partl.count() && intTypes.contains(partl[s])) { s++; } if(s < (int)partl.count() - 1) { qWarning("The argument `%s' seems syntactically wrong.", lt.latin1()); } if(s == (int)partl.count() - 1) { partl.remove(partl.at(s)); } lt = partl.join(" "); lt = lt.simplifyWhiteSpace(); } (*it) = lt; } QString fc = f.left(left); fc += '('; bool first = true; for(QStringList::Iterator it = types.begin(); it != types.end(); ++it) { if(!first) fc += ","; first = false; fc += *it; } fc += ')'; f = fc; } if(types.count() != args.count()) { qWarning("arguments do not match"); exit(1); } QByteArray data; QDataStream arg(data, IO_WriteOnly); uint i = 0; for(QStringList::Iterator it = types.begin(); it != types.end(); ++it) { marshall(arg, args, i, *it); } if((uint)i != args.count()) { qWarning("arguments do not match"); exit(1); } QCString foundApp; QCString foundObj; if(dcop->findObject(app, obj, f.latin1(), data, foundApp, foundObj)) { if(bAppIdOnly) puts(foundApp.data()); else printf("DCOPRef(%s,%s)\n", qStringToC(foundApp), qStringToC(foundObj)); return true; } return false; }
/** * Do the actual DCOP call */ int runDCOP(KStringList args, UserList users, Session session, const QString sessionName, bool readStdin, bool updateUserTime) { bool DCOPrefmode = false; QCString app; QCString objid; QCString function; KStringList params; DCOPClient *client = 0L; int retval = 0; if(!args.isEmpty() && args[0].find("DCOPRef(") == 0) { int delimPos = args[0].findRev(','); if(delimPos == -1) { cerr_ << "Error: '" << args[0] << "' is not a valid DCOP reference." << endl; exit(-1); } app = args[0].mid(8, delimPos - 8); delimPos++; objid = args[0].mid(delimPos, args[0].length() - delimPos - 1); if(args.count() > 1) function = args[1]; if(args.count() > 2) { params = args; params.remove(params.begin()); params.remove(params.begin()); } DCOPrefmode = true; } else { if(!args.isEmpty()) app = args[0]; if(args.count() > 1) objid = args[1]; if(args.count() > 2) function = args[2]; if(args.count() > 3) { params = args; params.remove(params.begin()); params.remove(params.begin()); params.remove(params.begin()); } } bool firstRun = true; UserList::Iterator it; QStringList sessions; bool presetDCOPServer = false; // char *dcopStr = 0L; QString dcopServer; for(it = users.begin(); it != users.end() || firstRun; ++it) { firstRun = false; // cout_ << "Iterating '" << it.key() << "'" << endl; if(session == QuerySessions) { QStringList sessions = dcopSessionList(it.key(), it.data()); if(sessions.isEmpty()) { if(users.count() <= 1) { cout_ << "No active sessions"; if(!(*it).isEmpty()) cout_ << " for user " << *it; cout_ << endl; } } else { cout_ << "Active sessions "; if(!(*it).isEmpty()) cout_ << "for user " << *it << " "; cout_ << ":" << endl; QStringList::Iterator sIt = sessions.begin(); for(; sIt != sessions.end(); ++sIt) cout_ << " " << *sIt << endl; cout_ << endl; } continue; } if(getenv("DCOPSERVER")) { sessions.append(getenv("DCOPSERVER")); presetDCOPServer = true; } if(users.count() > 1 || (users.count() == 1 && (getenv("DCOPSERVER") == 0 /*&& getenv( "DISPLAY" ) == 0*/))) { sessions = dcopSessionList(it.key(), it.data()); if(sessions.isEmpty()) { if(users.count() > 1) continue; else { cerr_ << "ERROR: No active KDE sessions!" << endl << "If you are sure there is one, please set the $DCOPSERVER variable manually" << endl << "before calling dcop." << endl; exit(-1); } } else if(!sessionName.isEmpty()) { if(sessions.contains(sessionName)) { sessions.clear(); sessions.append(sessionName); } else { cerr_ << "ERROR: The specified session doesn't exist!" << endl; exit(-1); } } else if(sessions.count() > 1 && session != AllSessions) { cerr_ << "ERROR: Multiple available KDE sessions!" << endl << "Please specify the correct session to use with --session or use the" << endl << "--all-sessions option to broadcast to all sessions." << endl; exit(-1); } } if(users.count() > 1 || (users.count() == 1 && (getenv("ICEAUTHORITY") == 0 || getenv("DISPLAY") == 0))) { // Check for ICE authority file and if the file can be read by us QString home = it.data(); QString iceFile = it.data() + "/.ICEauthority"; QFileInfo fi(iceFile); if(iceFile.isEmpty()) { cerr_ << "WARNING: Cannot determine home directory for user " << it.key() << "!" << endl << "Please check permissions or set the $ICEAUTHORITY variable manually before" << endl << "calling dcop." << endl; } else if(fi.exists()) { if(fi.isReadable()) { char *envStr = strdup(("ICEAUTHORITY=" + iceFile).ascii()); putenv(envStr); // cerr_ << "ice: " << envStr << endl; } else { cerr_ << "WARNING: ICE authority file " << iceFile << "is not readable by you!" << endl << "Please check permissions or set the $ICEAUTHORITY variable manually before" << endl << "calling dcop." << endl; } } else { if(users.count() > 1) continue; else { cerr_ << "WARNING: Cannot find ICE authority file " << iceFile << "!" << endl << "Please check permissions or set the $ICEAUTHORITY" << " variable manually before" << endl << "calling dcop." << endl; } } } // Main loop // If users is an empty list we're calling for the currently logged // in user. In this case we don't have a session, but still want // to iterate the loop once. QStringList::Iterator sIt = sessions.begin(); for(; sIt != sessions.end() || users.isEmpty(); ++sIt) { if(!presetDCOPServer && !users.isEmpty()) { QString dcopFile = it.data() + "/" + *sIt; QFile f(dcopFile); if(!f.open(IO_ReadOnly)) { cerr_ << "Can't open " << dcopFile << " for reading!" << endl; exit(-1); } QStringList l(QStringList::split('\n', f.readAll())); dcopServer = l.first(); if(dcopServer.isEmpty()) { cerr_ << "WARNING: Unable to determine DCOP server for session " << *sIt << "!" << endl << "Please check permissions or set the $DCOPSERVER variable manually before" << endl << "calling dcop." << endl; exit(-1); } } delete client; client = new DCOPClient; if(!dcopServer.isEmpty()) client->setServerAddress(dcopServer.ascii()); bool success = client->attach(); if(!success) { cerr_ << "ERROR: Couldn't attach to DCOP server!" << endl; retval = QMAX(retval, 1); if(users.isEmpty()) break; else continue; } dcop = client; int argscount = args.count(); if(DCOPrefmode) argscount++; switch(argscount) { case 0: queryApplications(""); break; case 1: if(endsWith(app, '*')) queryApplications(app); else queryObjects(app, ""); break; case 2: if(endsWith(objid, '*')) queryObjects(app, objid); else queryFunctions(app, objid); break; case 3: default: if(updateUserTime) sendUserTime(app); if(readStdin) { KStringList::Iterator replaceArg = params.end(); KStringList::Iterator it = params.begin(); for(; it != params.end(); ++it) if(*it == "%1") replaceArg = it; // Read from stdin until EOF and call function for each // read line while(!cin_.atEnd()) { QString buf = cin_.readLine(); if(replaceArg != params.end()) *replaceArg = buf.local8Bit(); if(!buf.isNull()) { int res = callFunction(app, objid, function, params); retval = QMAX(retval, res); } } } else { // Just call function // cout_ << "call " << app << ", " << objid << ", " << function << ", (params)" << endl; int res = callFunction(app, objid, function, params); retval = QMAX(retval, res); } break; } // Another sIt++ would make the loop infinite... if(users.isEmpty()) break; } // Another it++ would make the loop infinite... if(it == users.end()) break; } return retval; }
int main(int argc, char **argv) { bool readStdin = false; int numOptions = 0; QString user; Session session = DefaultSession; QString sessionName; bool updateUserTime = true; cin_.setEncoding(QTextStream::Locale); // Scan for command-line options first for(int pos = 1; pos <= argc - 1; pos++) { if(strcmp(argv[pos], "--help") == 0) showHelp(0); else if(strcmp(argv[pos], "--pipe") == 0) { readStdin = true; numOptions++; } else if(strcmp(argv[pos], "--user") == 0) { if(pos <= argc - 2) { user = QString::fromLocal8Bit(argv[pos + 1]); numOptions += 2; pos++; } else { cerr_ << "Missing username for '--user' option!" << endl << endl; showHelp(-1); } } else if(strcmp(argv[pos], "--session") == 0) { if(session == AllSessions) { cerr_ << "ERROR: --session cannot be mixed with --all-sessions!" << endl << endl; showHelp(-1); } else if(pos <= argc - 2) { sessionName = QString::fromLocal8Bit(argv[pos + 1]); numOptions += 2; pos++; } else { cerr_ << "Missing session name for '--session' option!" << endl << endl; showHelp(-1); } } else if(strcmp(argv[pos], "--all-users") == 0) { user = "******"; numOptions++; } else if(strcmp(argv[pos], "--list-sessions") == 0) { session = QuerySessions; numOptions++; } else if(strcmp(argv[pos], "--all-sessions") == 0) { if(!sessionName.isEmpty()) { cerr_ << "ERROR: --session cannot be mixed with --all-sessions!" << endl << endl; showHelp(-1); } session = AllSessions; numOptions++; } else if(strcmp(argv[pos], "--no-user-time") == 0) { updateUserTime = false; numOptions++; } else if(argv[pos][0] == '-') { cerr_ << "Unknown command-line option '" << argv[pos] << "'." << endl << endl; showHelp(-1); } else break; // End of options } argc -= numOptions; KStringList args; #ifdef DCOPQUIT if(argc > 1) { QCString prog = argv[numOptions + 1]; if(!prog.isEmpty()) { args.append(prog); // Pass as-is if it ends with a wildcard if(prog[prog.length() - 1] != '*') { // Strip a trailing -<PID> part. int i = prog.findRev('-'); if((i >= 0) && prog.mid(i + 1).toLong()) { prog = prog.left(i); } args.append("qt/" + prog); args.append("quit()"); } } } #else for(int i = numOptions; i < argc + numOptions - 1; i++) args.append(argv[i + 1]); #endif if(readStdin && args.count() < 3) { cerr_ << "--pipe option only supported for function calls!" << endl << endl; showHelp(-1); } if(user == "*" && args.count() < 3 && session != QuerySessions) { cerr_ << "ERROR: The --all-users option is only supported for function calls!" << endl << endl; showHelp(-1); } if(session == QuerySessions && !args.isEmpty()) { cerr_ << "ERROR: The --list-sessions option cannot be used for actual DCOP calls!" << endl << endl; showHelp(-1); } if(session == QuerySessions && user.isEmpty()) { cerr_ << "ERROR: The --list-sessions option can only be used with the --user or" << endl << "--all-users options!" << endl << endl; showHelp(-1); } if(session != DefaultSession && session != QuerySessions && args.count() < 3) { cerr_ << "ERROR: The --session and --all-sessions options are only supported for function" << endl << "calls!" << endl << endl; showHelp(-1); } UserList users; if(user == "*") users = userList(); else if(!user.isEmpty()) users[user] = userList()[user]; int retval = runDCOP(args, users, session, sessionName, readStdin, updateUserTime); return retval; }
int callFunction(const char *app, const char *obj, const char *func, const KStringList args) { QString f = func; // Qt is better with unicode strings, so use one. int left = f.find('('); int right = f.find(')'); if(right < left) { qWarning("parentheses do not match"); return (1); } if(left < 0) { // try to get the interface from the server bool ok = false; KStringList funcs = dcop->remoteFunctions(app, obj, &ok); QCString realfunc; if(!ok && args.isEmpty()) goto doit; if(!ok) { qWarning("object not accessible"); return (1); } for(const auto &it : funcs) { int l = it.find('('); int s; if(l > 0) s = it.findRev(' ', l); else s = it.find(' '); if(s < 0) s = 0; else s++; if(l > 0 && it.mid(s, l - s) == func) { realfunc = it.mid(s); const QString arguments = it.mid(l + 1, it.find(')') - l - 1); uint a = arguments.contains(','); if((a == 0 && !arguments.isEmpty()) || a > 0) a++; if(a == args.count()) break; } } if(realfunc.isEmpty()) { qWarning("no such function"); return (1); } f = realfunc; left = f.find('('); right = f.find(')'); } doit: if(left < 0) f += "()"; // This may seem expensive but is done only once per invocation // of dcop, so it should be OK. // // QStringList intTypes; intTypes << "int" << "unsigned" << "long" << "bool"; QStringList types; if(left > 0 && left + 1 < right - 1) { types = QStringList::split(',', f.mid(left + 1, right - left - 1)); for(QStringList::Iterator it = types.begin(); it != types.end(); ++it) { QString lt = (*it).simplifyWhiteSpace(); int s = lt.find(' '); // If there are spaces in the name, there may be two // reasons: the parameter name is still there, ie. // "QString URL" or it's a complicated int type, ie. // "unsigned long long int bool". // // if(s > 0) { QStringList partl = QStringList::split(' ', lt); // The zero'th part is -- at the very least -- a // type part. Any trailing parts *might* be extra // int-type keywords, or at most one may be the // parameter name. // // s = 1; while(s < static_cast< int >(partl.count()) && intTypes.contains(partl[s])) { s++; } if(s < static_cast< int >(partl.count()) - 1) { qWarning("The argument `%s' seems syntactically wrong.", lt.latin1()); } if(s == static_cast< int >(partl.count()) - 1) { partl.remove(partl.at(s)); } lt = partl.join(" "); lt = lt.simplifyWhiteSpace(); } (*it) = lt; } QString fc = f.left(left); fc += '('; bool first = true; for(QStringList::Iterator it = types.begin(); it != types.end(); ++it) { if(!first) fc += ","; first = false; fc += *it; } fc += ')'; f = fc; } QByteArray data, replyData; QCString replyType; QDataStream arg(data, IO_WriteOnly); uint i = 0; for(QStringList::Iterator it = types.begin(); it != types.end(); ++it) marshall(arg, args, i, *it); if(i != args.count()) { qWarning("arguments do not match"); return (1); } if(!dcop->call(app, obj, f.latin1(), data, replyType, replyData)) { qWarning("call failed"); return (1); } else { QDataStream reply(replyData, IO_ReadOnly); if(replyType != "void" && replyType != "ASYNC") { QCString replyString = demarshal(reply, replyType); if(!replyString.isEmpty()) printf("%s\n", replyString.data()); else printf("\n"); } } return 0; }