nxcl-0.9/0000755000175000017500000000000010764221531010777 5ustar mjj29mjj29nxcl-0.9/test/0000755000175000017500000000000010764221506011760 5ustar mjj29mjj29nxcl-0.9/test/.svn/0000755000175000017500000000000010764221506012644 5ustar mjj29mjj29nxcl-0.9/test/.svn/text-base/0000755000175000017500000000000010764221506014540 5ustar mjj29mjj29nxcl-0.9/test/.svn/text-base/notQttest.cpp.svn-base0000444000175000017500000001041710764221506020767 0ustar mjj29mjj29/*************************************************************************** notQttest.cpp - A test of some of the features in ../lib/notQt.cpp ------------------- begin : June 2007 copyright : (C) 2007 Embedded Software Foundry Ltd. (U.K.) : Author: Sebastian James email : seb@esfnet.co.uk ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #include #include #include #include "notQt.h" using namespace std; using namespace nxcl; ofstream debugLogFile; notQProcess p2; void processParseStdout() { string message = p2.readAllStandardOutput(); cout << "processParseStdout called, message is: " << message << endl; } void processParseStderr() { string message = p2.readAllStandardError(); cout << "processParseStderr called, message is: " << message << endl; } int main() { debugLogFile.open("/tmp/notQttest.log", ios::out|ios::trunc); // Test temporary files notQTemporaryFile tf; tf.open(); tf.write ("this is a temporary file, jim"); cout << "tmp filename is " << tf.fileName() << endl; tf.close(); // Test utilities string tstring = "\n\n this \t is\n a\t\t test string "; cout << "test string is '" << tstring << "'" << endl; cout << "simplify returns '" << notQtUtilities::simplify (tstring) << "'" << endl; tstring = "Nowhitespaceatall"; cout << "test string is '" << tstring << "'" << endl; cout << "simplify returns '" << notQtUtilities::simplify (tstring) << "'" << endl; tstring = "one two three\tfour"; vector v; notQtUtilities::splitString (tstring, ' ', v); cout << "v.size() = " << v.size() << endl; for (unsigned int i=0; i v2; notQtUtilities::splitString (tstring, 'h', v2); cout << "v2.size() = " << v2.size() << endl; for (unsigned int i=0; i args; // Always push_back the program first. args.push_back(program); args.push_back("teeout"); p.start (program, args); cout << "p.getPid=" << p.getPid() << endl; if (p.waitForStarted() == true) { string data = "Some input text"; p.writeIn (data); } else { cout << "not started" << endl; return -1; } // Test process that generates output bool finished = false; // program = "/usr/bin/eo"; program = "/usr/bin/tee"; args.clear(); // Always push_back the program first. args.push_back(program); args.push_back("hello"); // p2 is a global in this test /* FIXME: This needs to be changed, now that we got rid of boost signals. p2.readyReadStandardOutputSignal.connect (&processParseStdout); p2.readyReadStandardErrorSignal.connect (&processParseStderr); */ p2.start (program, args); cout << "p2.getPid=" << p2.getPid() << endl; if (p2.waitForStarted() == true) { string output; string errout; string instring = "data, data"; while (finished == false) { p2.probeProcess(); /* You can get the output without signals: output = p2.readAllStandardOutput(); errout = p2.readAllStandardError(); if (output.size()>0) { cout << program << " generated this output: " << output << endl; finished = true; } if (errout.size()>0) { cout << program << " generated this error: " << errout << endl; finished = true; } cout << "sleeping" << endl; */ usleep (1000000); p2.writeIn (instring); usleep (1000000); } } else { cout << "not started" << endl; return -1; } debugLogFile.close(); return 0; } nxcl-0.9/test/.svn/text-base/libtest.cpp.svn-base0000444000175000017500000000730010764221506020425 0ustar mjj29mjj29/*************************************************************************** libtest: A VERY simple command line test for the NXCL library ------------------- begin : June 2007 copyright : (C) 2007 Embedded Software Foundry Ltd. (U.K.) : Author: Sebastian James email : seb@esfnet.co.uk ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ /* * NB NB! This probably doesn't work. It shouldn't be hard to fix * though. It will be broken because I changed the signal handler * scheme. Seb. */ #include "nxclientlib.h" #include using namespace nxcl; using namespace std; ofstream debugLogFile; // Signal handlers void writeOut (string msg) { cout << "NXCL> " << msg << endl; } void stdinInfo (string msg) { cout << "nxssh<-stdin-" << endl << msg << endl; } void stdoutInfo (string msg) { cout << "nxssh-stdout->" << endl << msg << endl; } void stderrInfo (string msg) { cout << "nxssh-stderr->" << endl << msg << endl; } int main (int argc, char **argv) { NXClientLib lib; stringstream ss; ss << argv[2]; string un = ss.str(); ss.str(""); ss << argv[3]; string pw = ss.str(); ss.str(""); if (argc!=4) { cout << "Usage: libtest IP user pass" << endl; return -1; } debugLogFile.open("/tmp/libtest.log", ios::out|ios::trunc); lib.invokeNXSSH("default", argv[1], true, "", 22); lib.setUsername(un); lib.setPassword(pw); lib.setResolution(1280,1024); // This is the size of your screen lib.setDepth(24); lib.setRender(true); NXSessionData theSesh; // HARDCODED TEST CASE theSesh.sessionName = "TEST"; theSesh.sessionType = "unix-gnome"; theSesh.cache = 8; theSesh.images = 32; theSesh.linkType = "adsl"; theSesh.render = true; theSesh.backingstore = "when_requested"; theSesh.imageCompressionMethod = 2; // theSesh.imageCompressionLevel; theSesh.geometry = "800x600+0+0"; // This'll be the size of the session theSesh.keyboard = "defkeymap"; theSesh.kbtype = "pc102/defkeymap"; theSesh.media = false; theSesh.agentServer = ""; theSesh.agentUser = ""; theSesh.agentPass = ""; theSesh.cups = 0; theSesh.suspended = false; theSesh.fullscreen = true; // If true, theSesh.geometry is ignored lib.setSessionData(&theSesh); // Set the handler you would like to output messages to the user. We'll just use stdout for this test. //lib.callbackWriteSignal.connect (&writeOut); // If you want a nice quiet session, leave these signals unconnected /* lib.stdinSignal.connect (&stdinInfo); lib.stdoutSignal.connect (&stdoutInfo); lib.stderrSignal.connect (&stderrInfo); */ //notQProcess& p = lib.getNXSSHProcess(); notQProcess* p; while ((lib.getIsFinished()) == false) { // We need to repeatedly check if there is any output to parse. if (lib.getReadyForProxy() == false) { p = lib.getNXSSHProcess(); p->probeProcess(); } else { p = lib.getNXSSHProcess(); p->probeProcess(); p = lib.getNXProxyProcess(); p->probeProcess(); } usleep (1000); } writeOut ("Program finished."); debugLogFile.close(); return 0; } nxcl-0.9/test/.svn/text-base/Makefile.am.svn-base0000444000175000017500000000110210764221506020301 0ustar mjj29mjj29AM_CPPFLAGS = @PACKAGE_CFLAGS@ -DPACKAGE_DATA_DIR=\""$(datadir)"\" -DLOCALEDIR=\"$(localedir)\" -DPACKAGE_BIN_DIR=\""$(bindir)"\" $(DBUS_CFLAGS) INCLUDES = -I../lib bin_PROGRAMS = libtest notQttest if WITH_NXCMD bin_PROGRAMS += nxcmd endif if DEBUG AM_CPPFLAGS += -DDEBUG endif libtest_SOURCES = libtest.cpp libtest_LDADD = @PACKAGE_LIBS@ $(LIBINTL) -L../lib -lnxcl notQttest_SOURCES = notQttest.cpp notQttest_LDADD = @PACKAGE_LIBS@ $(LIBINTL) -L../lib -lnxcl nxcmd_SOURCES = nxcmd.cpp nxcmd_LDADD = @PACKAGE_LIBS@ $(LIBINTL) $(DBUS_LIBS) #pkginclude_HEADERS = header.h nxcl-0.9/test/.svn/text-base/nxcmd.cpp.svn-base0000444000175000017500000004000610764221506020070 0ustar mjj29mjj29/*************************************************************************** nxcmd: A simple command line test for the NXCL dbus daemon. ------------------- begin : June 2007 copyright : (C) 2007 Embedded Software Foundry Ltd. (U.K.) : Author: Sebastian James email : seb@esfnet.co.uk ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ /*! * See ../nxcl/main.cpp for general notes on the nxcl program. * * This program will fork a process and run nxcl, then it will send * user, password and some settings to nxcl using a dbus * connection. nxcl will then start up the NX connection for you. * * This is a very hacked together program, part C, part C++, but it * serves its purpose of demonstrating the techniques you'll need to * write a simple client to nxcl. */ #include #include extern "C" { #include #include #define DBUS_API_SUBJECT_TO_CHANGE 1 #include #include #include #include #include #include } // This is the only dependency on nxcl here. If you want, all you have // to do is copy the NXConfigData structure out of nxdata.h and you // remove the dependency. #include "../lib/nxdata.h" using namespace std; // Default NoMachine certificate for FALLBACK. Don't do it this way in // your code. Instead, ship a default key in a file and reference // that. string cert("-----BEGIN DSA PRIVATE KEY-----\nMIIBuwIBAAKBgQCXv9AzQXjxvXWC1qu3CdEqskX9YomTfyG865gb4D02ZwWuRU/9\nC3I9/bEWLdaWgJYXIcFJsMCIkmWjjeSZyTmeoypI1iLifTHUxn3b7WNWi8AzKcVF\naBsBGiljsop9NiD1mEpA0G+nHHrhvTXz7pUvYrsrXcdMyM6rxqn77nbbnwIVALCi\nxFdHZADw5KAVZI7r6QatEkqLAoGBAI4L1TQGFkq5xQ/nIIciW8setAAIyrcWdK/z\n5/ZPeELdq70KDJxoLf81NL/8uIc4PoNyTRJjtT3R4f8Az1TsZWeh2+ReCEJxDWgG\nfbk2YhRqoQTtXPFsI4qvzBWct42WonWqyyb1bPBHk+JmXFscJu5yFQ+JUVNsENpY\n+Gkz3HqTAoGANlgcCuA4wrC+3Cic9CFkqiwO/Rn1vk8dvGuEQqFJ6f6LVfPfRTfa\nQU7TGVLk2CzY4dasrwxJ1f6FsT8DHTNGnxELPKRuLstGrFY/PR7KeafeFZDf+fJ3\nmbX5nxrld3wi5titTnX+8s4IKv29HJguPvOK/SI7cjzA+SqNfD7qEo8CFDIm1xRf\n8xAPsSKs6yZ6j1FNklfu\n-----END DSA PRIVATE KEY-----"); // Used in receiveSession as the return value #define REPLY_REQUIRED 1 #define NEW_CONNECTION 2 #define SERVER_CAPACITY 3 /*! * Send all the settings in a single dbus signal. */ static int sendSettings (DBusConnection *bus, nxcl::NXConfigData& cfg); /*! * Listen to the dbus, waiting for a signal to say either that * connection is in progress, or giving us a list of possible sessions * we could connect to. Return true if nxcl requires a reply such * as "please resume session 1". */ static int receiveSession (DBusConnection* conn); /*! * Send a signal containing the identifier for the NX session that the * user would like to start. */ static int sendReply (DBusConnection *bus, int sessionNum); /*! * Send a signal containing the identifier for the NX session that the * user would like to terminate. */ static int terminateSession (DBusConnection *bus, int sessionNum); /*! * Lazily use some globals, as this is just an example command line program. */ string dbusSendInterface; string dbusRecvInterface; string dbusMatchString; int main (int argc, char **argv) { nxcl::NXConfigData cfg; DBusConnection *conn; DBusError error; int ret; int theError; pid_t pid; bool gotName = false; int i = 0; if (argc != 5) { cout << "NXCMD> Usage: nxcmd IP/DNSName user pass sessiontype\n"; cout << "NXCMD> Eg: nxcmd 192.168.0.1 me mypass unix-gnome\n"; return -1; } cout << "NXCMD> Starting...\n"; /* Get a connection to the session bus */ dbus_error_init (&error); conn = dbus_bus_get (DBUS_BUS_SESSION, &error); if (!conn) { cerr << "Failed to connect to the D-BUS daemon: " << error.message << endl; dbus_error_free (&error); return 1; } while (gotName == false) { stringstream ss; string base = "org.freenx.nxcl."; ss << base << "client" << i; dbusSendInterface = ss.str(); ss.str(""); ss << base << "nxcl" << i; dbusRecvInterface = ss.str(); ss.str(""); ss << "type='signal',interface='org.freenx.nxcl.nxcl" << i << "'"; dbusMatchString = ss.str(); // We request a name on the bus which is the same string as the send interface. ret = dbus_bus_request_name (conn, dbusSendInterface.c_str(), DBUS_NAME_FLAG_REPLACE_EXISTING, &error); if (dbus_error_is_set(&error)) { cerr << "NXCMD> Name Error (" << error.message << ")\n"; dbus_error_free(&error); } if (DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER != ret) { cerr << "NXCMD> Couldn't get the name; trying another\n"; i++; } else { cout << "NXCMD> Got the name '" << dbusSendInterface << "' on the dbus\n"; gotName = true; } } stringstream arg; arg << i; /* fork and exec the nxcl */ pid = fork(); switch (pid) { case -1: cerr << "Can't fork()!" << endl; exit (-1); case 0: // This is the CHILD process // Allocate memory for the program arguments // 1+ to allow space for NULL terminating pointer execl (PACKAGE_BIN_DIR"/nxcl", "nxcl", arg.str().c_str(), static_cast(NULL)); // If process returns, error occurred theError = errno; // This'll get picked up by parseResponse cerr << "NXCMD> Process error: " << pid << " crashed. errno:" << theError << endl; // Child should exit now. exit(-1); default: // This is the PARENT process cout << "NXCMD> forked the nxcl process; continuing.\n"; break; } /* Prepare interface - add a rule for which messages we want to see - those that are sent to us from the nxcl connection. */ dbus_bus_add_match(conn, dbusMatchString.c_str(), &error); dbus_connection_flush (conn); if (dbus_error_is_set(&error)) { cerr << "NXCMD> Match Error (" << error.message << ")\n"; exit(1); } else { cout << "NXCMD> Added match '" << dbusMatchString << "'\n"; } // Crude 2 second wait to let nxcl get going before we send // the settings. This _must_ be more sophisticated in your // application ;) sleep (2); cout << "NXCMD> Configure session\n"; // We now set up the config data structure. We take user, host // and pass from the command line, but for the sake of // simplicity, we hard-code the rest of the settings here. cfg.serverHost = argv[1]; cfg.serverPort = 22; cfg.sessionUser = argv[2]; cfg.sessionPass = argv[3]; cfg.sessionName = "nxcmd"; cfg.sessionType = argv[4]; cfg.cache = 8; cfg.images = 32; cfg.linkType = "adsl"; cfg.render = true; cfg.backingstore = "when_requested"; cfg.imageCompressionMethod = 2; cfg.imageCompressionLevel = 1; cfg.geometry = "800x600+0+0"; cfg.keyboard = "defkeymap"; cfg.kbtype = "pc105/defkeymap"; cfg.media = false; cfg.agentServer = ""; cfg.agentUser = ""; cfg.agentPass = ""; cfg.cups = 0; cfg.encryption = true; cfg.key = cert; cfg.fullscreen = false; // If true, ignore cfg.geometry. cout << "NXCMD> Sending settings\n"; // ...and then send it on dbus. sendSettings (conn, cfg); cout << "NXCMD> Sent settings\n"; // In real application, we'd now listen on the dbus for a list // of sessions we might be able to re-connect to, or // confirmation that a session is starting. Then we could return. bool done = false; while (false == done) { if (REPLY_REQUIRED == (ret = receiveSession (conn))) { // Need to send back a reply saying which connection // to reconnect. cout << "NXCMD> Please choose a session. 0 for the first, etc.\nT0 to terminate the first, etc\n"; if (cfg.sessionType != "shadow") { cout << "Enter -1 to start a new session\n"; } // Choose 0 for first connection, 1 for next etc, or // <0 for a new connection, even if there are existing // sessions. int connNum = 0; string response; cin >> response; stringstream ss; if (response[0] == 'T') { ss << response.substr(1); ss >> connNum; cout << "NXCMD> Terminating session " << connNum << endl; terminateSession (conn, connNum); } else { ss << response; ss >> connNum; sendReply (conn, connNum); if (connNum < 0) { cout << "NXCMD> Starting new NX session\n"; } else { cout << "NXCMD> Attaching to session " << connNum << endl; } done = true; } } else if (SERVER_CAPACITY == ret) { // Have run out of capacity (licences) on the server. done = true; } else { cout << "NXCMD> Starting new NX session\n"; done = true; } } // wait and block for nxcl process to end before exiting. int status = 0; wait (&status); return 0; } static int sendSettings (DBusConnection *bus, nxcl::NXConfigData& cfg) { cout << "NXCMD> sendSettings called\n"; DBusMessage *message; /* Create a new setting signal on the "org.freenx.nxcl.client" * interface, from the object "/org/freenx/nxcl/dbus/settingSignal". */ message = dbus_message_new_signal ("/org/freenx/nxcl/dbus/settingSignal", dbusSendInterface.c_str(), "sessionConfig"); if (NULL == message) { cerr << "NXCMD> Message Null\n"; return -1; } int media=0, enc=0, fs=0; if (cfg.media == true) { media = 1; } if (cfg.encryption == true) { enc = 1; } if (cfg.fullscreen == true) { fs = 1; } dbus_message_append_args (message, DBUS_TYPE_STRING, &cfg.serverHost, //0 DBUS_TYPE_INT32, &cfg.serverPort, DBUS_TYPE_STRING, &cfg.sessionUser, //2 DBUS_TYPE_STRING, &cfg.sessionPass, DBUS_TYPE_STRING, &cfg.sessionName, //4 DBUS_TYPE_STRING, &cfg.sessionType, DBUS_TYPE_INT32, &cfg.cache, //6 DBUS_TYPE_INT32, &cfg.images, DBUS_TYPE_STRING, &cfg.linkType, //8 DBUS_TYPE_INT32, &cfg.render, DBUS_TYPE_STRING, &cfg.backingstore,//10 DBUS_TYPE_INT32, &cfg.imageCompressionMethod, DBUS_TYPE_INT32, &cfg.imageCompressionLevel, //12 DBUS_TYPE_STRING, &cfg.geometry, DBUS_TYPE_STRING, &cfg.keyboard, //14 DBUS_TYPE_STRING, &cfg.kbtype, DBUS_TYPE_INT32, &media, //16 DBUS_TYPE_STRING, &cfg.agentServer, DBUS_TYPE_STRING, &cfg.agentUser, //18 DBUS_TYPE_STRING, &cfg.agentPass, DBUS_TYPE_INT32, &cfg.cups, //20 DBUS_TYPE_STRING, &cfg.key, DBUS_TYPE_INT32, &enc, //22 DBUS_TYPE_INT32, &fs, DBUS_TYPE_STRING, &cfg.customCommand,//24 DBUS_TYPE_INVALID); /* Send the signal */ if (!dbus_connection_send (bus, message, NULL)) { cerr << "NXCMD> Out Of Memory!\n"; exit(1); } /* Clean up */ dbus_message_unref (message); dbus_connection_flush (bus); return 1; } static int sendReply (DBusConnection *bus, int sessionNum) { DBusMessage *message; DBusMessageIter args; /* Create a new session choice signal on the "org.freenx.nxcl.client" * interface, from the object "/org/freenx/nxcl/dbus/sessionChoice". */ message = dbus_message_new_signal ("/org/freenx/nxcl/dbus/sessionChoice", dbusSendInterface.c_str(), "sessionChoice"); if (NULL == message) { cerr << "NXCMD> Message Null\n"; return -1; } dbus_message_iter_init_append (message, &args); if (!dbus_message_iter_append_basic (&args, DBUS_TYPE_INT32, (const void*)&sessionNum)) { cerr << "NXCMD> Out Of Memory!\n"; exit(1); } /* Send the signal */ if (!dbus_connection_send (bus, message, NULL)) { cerr << "NXCMD> Out Of Memory!\n"; exit(1); } /* Clean up */ dbus_message_unref (message); dbus_connection_flush (bus); return 1; } static int terminateSession (DBusConnection *bus, int sessionNum) { DBusMessage *message; DBusMessageIter args; /* Create a new session choice signal on the "org.freenx.nxcl.client" * interface, from the object "/org/freenx/nxcl/dbus/sessionChoice". */ message = dbus_message_new_signal ("/org/freenx/nxcl/dbus/sessionChoice", dbusSendInterface.c_str(), "terminateSession"); if (NULL == message) { cerr << "NXCMD> Message Null\n"; return -1; } dbus_message_iter_init_append (message, &args); if (!dbus_message_iter_append_basic (&args, DBUS_TYPE_INT32, (const void*)&sessionNum)) { cerr << "NXCMD> Out Of Memory!\n"; exit(1); } /* Send the signal */ if (!dbus_connection_send (bus, message, NULL)) { cerr << "NXCMD> Out Of Memory!\n"; exit(1); } /* Clean up */ dbus_message_unref (message); dbus_connection_flush (bus); return 1; } /* * Wait for and receive a message with available sessions, or a * message saying there are no available sessions */ static int receiveSession (DBusConnection* conn) { DBusMessage * message; DBusMessageIter args; DBusError error; char * parameter = NULL; dbus_int32_t iparam = 0, t = 0; int count = 0; bool sessions_obtained = false; int rtn = 0; stringstream ss; cout << "NXCMD> In receiveSession, listening to " << dbusRecvInterface << "\n"; dbus_error_init (&error); int sessionNum = 0; // loop listening for signals being emitted while (sessions_obtained == false) { if (dbus_error_is_set(&error)) { cerr << "NXCMD> Name Error (" << error.message << ")\n"; dbus_error_free(&error); } count = 0; // non blocking read of the next available message dbus_connection_read_write(conn, 0); message = dbus_connection_pop_message(conn); // loop again if we haven't read a message if (NULL == message) { sleep (1); continue; } // check if the message is a signal from the // correct interface and with the correct name if (dbus_message_is_signal (message, dbusRecvInterface.c_str(), "AvailableSession")) { if (!dbus_message_iter_init (message, &args)) { cerr << "NXCMD> Message has no arguments!\n"; dbus_connection_flush (conn); dbus_message_unref (message); continue; } if (DBUS_TYPE_INT32 != dbus_message_iter_get_arg_type (&args)) { cerr << "NXCMD> First argument is not int32!\n"; } else { dbus_message_iter_get_basic (&args, &iparam); if (sessionNum == 0) { cout << "NXCMD> Available sessions:\n"; } cout << sessionNum++ << ": " << iparam; count++; } // read the parameters - something like: while (dbus_message_iter_next (&args)) { if (DBUS_TYPE_STRING == (t = dbus_message_iter_get_arg_type(&args))) { dbus_message_iter_get_basic(&args, ¶meter); cout << " " << parameter; ss.str(""); ss << parameter; count++; } else if (t == DBUS_TYPE_INT32) { dbus_message_iter_get_basic (&args, &iparam); cout << " " << iparam; ss.str(""); ss << iparam; count++; } else { cerr << "NXCMD> Error, parameter is not string or int.\n"; } // Now we'd do something sensible with the data... } cout << endl; } else if (dbus_message_is_signal (message, dbusRecvInterface.c_str(), "NoMoreAvailable")) { sessions_obtained = true; rtn = REPLY_REQUIRED; } else if (dbus_message_is_signal (message, dbusRecvInterface.c_str(), "Connecting")) { sessions_obtained = true; rtn = NEW_CONNECTION; } else if (dbus_message_is_signal (message, dbusRecvInterface.c_str(), "ServerCapacityReached")) { sessions_obtained = true; rtn = SERVER_CAPACITY; } else { #ifdef DEBUG cout << "NXCMD> None of the above...\n"; if (!dbus_message_iter_init(message, &args)) { cerr << "NXCMD> Message has no arguments!\n"; dbus_connection_flush (conn); dbus_message_unref (message); continue; } if (DBUS_TYPE_STRING == (t = dbus_message_iter_get_arg_type(&args))) { dbus_message_iter_get_basic(&args, ¶meter); cout << "NXCMD> Parameter: " << parameter << endl; } #endif } dbus_connection_flush (conn); dbus_message_unref (message); } // while() return rtn; } nxcl-0.9/test/.svn/prop-base/0000755000175000017500000000000010764221506014534 5ustar mjj29mjj29nxcl-0.9/test/.svn/props/0000755000175000017500000000000010764221506014007 5ustar mjj29mjj29nxcl-0.9/test/.svn/tmp/0000755000175000017500000000000010764221506013444 5ustar mjj29mjj29nxcl-0.9/test/.svn/tmp/text-base/0000755000175000017500000000000010764221506015340 5ustar mjj29mjj29nxcl-0.9/test/.svn/tmp/prop-base/0000755000175000017500000000000010764221506015334 5ustar mjj29mjj29nxcl-0.9/test/.svn/tmp/props/0000755000175000017500000000000010764221506014607 5ustar mjj29mjj29nxcl-0.9/test/.svn/entries0000444000175000017500000000132110764221506014233 0ustar mjj29mjj298 dir 500 svn://svn.berlios.de/freenx/tags/nxcl-0.9/test svn://svn.berlios.de/freenx 2008-01-30T07:57:35.836436Z 456 gwright svn:special svn:externals svn:needs-lock 80778403-ebee-0310-8e0a-e86a689f3fff notQttest.cpp file 2008-03-07T11:13:10.000000Z 46f7177adc26545d956111a437837cee 2007-09-11T14:59:12.694754Z 375 sebjames libtest.cpp file 2008-03-07T11:13:10.000000Z b6984832a9cec754a9249b66936b29cc 2007-09-11T14:59:12.694754Z 375 sebjames Makefile.am file 2008-03-07T11:13:10.000000Z cf4d8f560d6c535e0dbe6f39eaeaea4b 2008-01-30T07:57:35.836436Z 456 gwright nxcmd.cpp file 2008-03-07T11:13:10.000000Z 1cd662cddf2c8e1c254829572d255a9d 2007-09-11T14:59:12.694754Z 375 sebjames nxcl-0.9/test/.svn/format0000444000175000017500000000000210764221506014045 0ustar mjj29mjj298 nxcl-0.9/test/notQttest.cpp0000644000175000017500000001041710764221506014474 0ustar mjj29mjj29/*************************************************************************** notQttest.cpp - A test of some of the features in ../lib/notQt.cpp ------------------- begin : June 2007 copyright : (C) 2007 Embedded Software Foundry Ltd. (U.K.) : Author: Sebastian James email : seb@esfnet.co.uk ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #include #include #include #include "notQt.h" using namespace std; using namespace nxcl; ofstream debugLogFile; notQProcess p2; void processParseStdout() { string message = p2.readAllStandardOutput(); cout << "processParseStdout called, message is: " << message << endl; } void processParseStderr() { string message = p2.readAllStandardError(); cout << "processParseStderr called, message is: " << message << endl; } int main() { debugLogFile.open("/tmp/notQttest.log", ios::out|ios::trunc); // Test temporary files notQTemporaryFile tf; tf.open(); tf.write ("this is a temporary file, jim"); cout << "tmp filename is " << tf.fileName() << endl; tf.close(); // Test utilities string tstring = "\n\n this \t is\n a\t\t test string "; cout << "test string is '" << tstring << "'" << endl; cout << "simplify returns '" << notQtUtilities::simplify (tstring) << "'" << endl; tstring = "Nowhitespaceatall"; cout << "test string is '" << tstring << "'" << endl; cout << "simplify returns '" << notQtUtilities::simplify (tstring) << "'" << endl; tstring = "one two three\tfour"; vector v; notQtUtilities::splitString (tstring, ' ', v); cout << "v.size() = " << v.size() << endl; for (unsigned int i=0; i v2; notQtUtilities::splitString (tstring, 'h', v2); cout << "v2.size() = " << v2.size() << endl; for (unsigned int i=0; i args; // Always push_back the program first. args.push_back(program); args.push_back("teeout"); p.start (program, args); cout << "p.getPid=" << p.getPid() << endl; if (p.waitForStarted() == true) { string data = "Some input text"; p.writeIn (data); } else { cout << "not started" << endl; return -1; } // Test process that generates output bool finished = false; // program = "/usr/bin/eo"; program = "/usr/bin/tee"; args.clear(); // Always push_back the program first. args.push_back(program); args.push_back("hello"); // p2 is a global in this test /* FIXME: This needs to be changed, now that we got rid of boost signals. p2.readyReadStandardOutputSignal.connect (&processParseStdout); p2.readyReadStandardErrorSignal.connect (&processParseStderr); */ p2.start (program, args); cout << "p2.getPid=" << p2.getPid() << endl; if (p2.waitForStarted() == true) { string output; string errout; string instring = "data, data"; while (finished == false) { p2.probeProcess(); /* You can get the output without signals: output = p2.readAllStandardOutput(); errout = p2.readAllStandardError(); if (output.size()>0) { cout << program << " generated this output: " << output << endl; finished = true; } if (errout.size()>0) { cout << program << " generated this error: " << errout << endl; finished = true; } cout << "sleeping" << endl; */ usleep (1000000); p2.writeIn (instring); usleep (1000000); } } else { cout << "not started" << endl; return -1; } debugLogFile.close(); return 0; } nxcl-0.9/test/libtest.cpp0000644000175000017500000000730010764221506014132 0ustar mjj29mjj29/*************************************************************************** libtest: A VERY simple command line test for the NXCL library ------------------- begin : June 2007 copyright : (C) 2007 Embedded Software Foundry Ltd. (U.K.) : Author: Sebastian James email : seb@esfnet.co.uk ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ /* * NB NB! This probably doesn't work. It shouldn't be hard to fix * though. It will be broken because I changed the signal handler * scheme. Seb. */ #include "nxclientlib.h" #include using namespace nxcl; using namespace std; ofstream debugLogFile; // Signal handlers void writeOut (string msg) { cout << "NXCL> " << msg << endl; } void stdinInfo (string msg) { cout << "nxssh<-stdin-" << endl << msg << endl; } void stdoutInfo (string msg) { cout << "nxssh-stdout->" << endl << msg << endl; } void stderrInfo (string msg) { cout << "nxssh-stderr->" << endl << msg << endl; } int main (int argc, char **argv) { NXClientLib lib; stringstream ss; ss << argv[2]; string un = ss.str(); ss.str(""); ss << argv[3]; string pw = ss.str(); ss.str(""); if (argc!=4) { cout << "Usage: libtest IP user pass" << endl; return -1; } debugLogFile.open("/tmp/libtest.log", ios::out|ios::trunc); lib.invokeNXSSH("default", argv[1], true, "", 22); lib.setUsername(un); lib.setPassword(pw); lib.setResolution(1280,1024); // This is the size of your screen lib.setDepth(24); lib.setRender(true); NXSessionData theSesh; // HARDCODED TEST CASE theSesh.sessionName = "TEST"; theSesh.sessionType = "unix-gnome"; theSesh.cache = 8; theSesh.images = 32; theSesh.linkType = "adsl"; theSesh.render = true; theSesh.backingstore = "when_requested"; theSesh.imageCompressionMethod = 2; // theSesh.imageCompressionLevel; theSesh.geometry = "800x600+0+0"; // This'll be the size of the session theSesh.keyboard = "defkeymap"; theSesh.kbtype = "pc102/defkeymap"; theSesh.media = false; theSesh.agentServer = ""; theSesh.agentUser = ""; theSesh.agentPass = ""; theSesh.cups = 0; theSesh.suspended = false; theSesh.fullscreen = true; // If true, theSesh.geometry is ignored lib.setSessionData(&theSesh); // Set the handler you would like to output messages to the user. We'll just use stdout for this test. //lib.callbackWriteSignal.connect (&writeOut); // If you want a nice quiet session, leave these signals unconnected /* lib.stdinSignal.connect (&stdinInfo); lib.stdoutSignal.connect (&stdoutInfo); lib.stderrSignal.connect (&stderrInfo); */ //notQProcess& p = lib.getNXSSHProcess(); notQProcess* p; while ((lib.getIsFinished()) == false) { // We need to repeatedly check if there is any output to parse. if (lib.getReadyForProxy() == false) { p = lib.getNXSSHProcess(); p->probeProcess(); } else { p = lib.getNXSSHProcess(); p->probeProcess(); p = lib.getNXProxyProcess(); p->probeProcess(); } usleep (1000); } writeOut ("Program finished."); debugLogFile.close(); return 0; } nxcl-0.9/test/Makefile.am0000644000175000017500000000110210764221506014006 0ustar mjj29mjj29AM_CPPFLAGS = @PACKAGE_CFLAGS@ -DPACKAGE_DATA_DIR=\""$(datadir)"\" -DLOCALEDIR=\"$(localedir)\" -DPACKAGE_BIN_DIR=\""$(bindir)"\" $(DBUS_CFLAGS) INCLUDES = -I../lib bin_PROGRAMS = libtest notQttest if WITH_NXCMD bin_PROGRAMS += nxcmd endif if DEBUG AM_CPPFLAGS += -DDEBUG endif libtest_SOURCES = libtest.cpp libtest_LDADD = @PACKAGE_LIBS@ $(LIBINTL) -L../lib -lnxcl notQttest_SOURCES = notQttest.cpp notQttest_LDADD = @PACKAGE_LIBS@ $(LIBINTL) -L../lib -lnxcl nxcmd_SOURCES = nxcmd.cpp nxcmd_LDADD = @PACKAGE_LIBS@ $(LIBINTL) $(DBUS_LIBS) #pkginclude_HEADERS = header.h nxcl-0.9/test/nxcmd.cpp0000644000175000017500000004000610764221506013575 0ustar mjj29mjj29/*************************************************************************** nxcmd: A simple command line test for the NXCL dbus daemon. ------------------- begin : June 2007 copyright : (C) 2007 Embedded Software Foundry Ltd. (U.K.) : Author: Sebastian James email : seb@esfnet.co.uk ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ /*! * See ../nxcl/main.cpp for general notes on the nxcl program. * * This program will fork a process and run nxcl, then it will send * user, password and some settings to nxcl using a dbus * connection. nxcl will then start up the NX connection for you. * * This is a very hacked together program, part C, part C++, but it * serves its purpose of demonstrating the techniques you'll need to * write a simple client to nxcl. */ #include #include extern "C" { #include #include #define DBUS_API_SUBJECT_TO_CHANGE 1 #include #include #include #include #include #include } // This is the only dependency on nxcl here. If you want, all you have // to do is copy the NXConfigData structure out of nxdata.h and you // remove the dependency. #include "../lib/nxdata.h" using namespace std; // Default NoMachine certificate for FALLBACK. Don't do it this way in // your code. Instead, ship a default key in a file and reference // that. string cert("-----BEGIN DSA PRIVATE KEY-----\nMIIBuwIBAAKBgQCXv9AzQXjxvXWC1qu3CdEqskX9YomTfyG865gb4D02ZwWuRU/9\nC3I9/bEWLdaWgJYXIcFJsMCIkmWjjeSZyTmeoypI1iLifTHUxn3b7WNWi8AzKcVF\naBsBGiljsop9NiD1mEpA0G+nHHrhvTXz7pUvYrsrXcdMyM6rxqn77nbbnwIVALCi\nxFdHZADw5KAVZI7r6QatEkqLAoGBAI4L1TQGFkq5xQ/nIIciW8setAAIyrcWdK/z\n5/ZPeELdq70KDJxoLf81NL/8uIc4PoNyTRJjtT3R4f8Az1TsZWeh2+ReCEJxDWgG\nfbk2YhRqoQTtXPFsI4qvzBWct42WonWqyyb1bPBHk+JmXFscJu5yFQ+JUVNsENpY\n+Gkz3HqTAoGANlgcCuA4wrC+3Cic9CFkqiwO/Rn1vk8dvGuEQqFJ6f6LVfPfRTfa\nQU7TGVLk2CzY4dasrwxJ1f6FsT8DHTNGnxELPKRuLstGrFY/PR7KeafeFZDf+fJ3\nmbX5nxrld3wi5titTnX+8s4IKv29HJguPvOK/SI7cjzA+SqNfD7qEo8CFDIm1xRf\n8xAPsSKs6yZ6j1FNklfu\n-----END DSA PRIVATE KEY-----"); // Used in receiveSession as the return value #define REPLY_REQUIRED 1 #define NEW_CONNECTION 2 #define SERVER_CAPACITY 3 /*! * Send all the settings in a single dbus signal. */ static int sendSettings (DBusConnection *bus, nxcl::NXConfigData& cfg); /*! * Listen to the dbus, waiting for a signal to say either that * connection is in progress, or giving us a list of possible sessions * we could connect to. Return true if nxcl requires a reply such * as "please resume session 1". */ static int receiveSession (DBusConnection* conn); /*! * Send a signal containing the identifier for the NX session that the * user would like to start. */ static int sendReply (DBusConnection *bus, int sessionNum); /*! * Send a signal containing the identifier for the NX session that the * user would like to terminate. */ static int terminateSession (DBusConnection *bus, int sessionNum); /*! * Lazily use some globals, as this is just an example command line program. */ string dbusSendInterface; string dbusRecvInterface; string dbusMatchString; int main (int argc, char **argv) { nxcl::NXConfigData cfg; DBusConnection *conn; DBusError error; int ret; int theError; pid_t pid; bool gotName = false; int i = 0; if (argc != 5) { cout << "NXCMD> Usage: nxcmd IP/DNSName user pass sessiontype\n"; cout << "NXCMD> Eg: nxcmd 192.168.0.1 me mypass unix-gnome\n"; return -1; } cout << "NXCMD> Starting...\n"; /* Get a connection to the session bus */ dbus_error_init (&error); conn = dbus_bus_get (DBUS_BUS_SESSION, &error); if (!conn) { cerr << "Failed to connect to the D-BUS daemon: " << error.message << endl; dbus_error_free (&error); return 1; } while (gotName == false) { stringstream ss; string base = "org.freenx.nxcl."; ss << base << "client" << i; dbusSendInterface = ss.str(); ss.str(""); ss << base << "nxcl" << i; dbusRecvInterface = ss.str(); ss.str(""); ss << "type='signal',interface='org.freenx.nxcl.nxcl" << i << "'"; dbusMatchString = ss.str(); // We request a name on the bus which is the same string as the send interface. ret = dbus_bus_request_name (conn, dbusSendInterface.c_str(), DBUS_NAME_FLAG_REPLACE_EXISTING, &error); if (dbus_error_is_set(&error)) { cerr << "NXCMD> Name Error (" << error.message << ")\n"; dbus_error_free(&error); } if (DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER != ret) { cerr << "NXCMD> Couldn't get the name; trying another\n"; i++; } else { cout << "NXCMD> Got the name '" << dbusSendInterface << "' on the dbus\n"; gotName = true; } } stringstream arg; arg << i; /* fork and exec the nxcl */ pid = fork(); switch (pid) { case -1: cerr << "Can't fork()!" << endl; exit (-1); case 0: // This is the CHILD process // Allocate memory for the program arguments // 1+ to allow space for NULL terminating pointer execl (PACKAGE_BIN_DIR"/nxcl", "nxcl", arg.str().c_str(), static_cast(NULL)); // If process returns, error occurred theError = errno; // This'll get picked up by parseResponse cerr << "NXCMD> Process error: " << pid << " crashed. errno:" << theError << endl; // Child should exit now. exit(-1); default: // This is the PARENT process cout << "NXCMD> forked the nxcl process; continuing.\n"; break; } /* Prepare interface - add a rule for which messages we want to see - those that are sent to us from the nxcl connection. */ dbus_bus_add_match(conn, dbusMatchString.c_str(), &error); dbus_connection_flush (conn); if (dbus_error_is_set(&error)) { cerr << "NXCMD> Match Error (" << error.message << ")\n"; exit(1); } else { cout << "NXCMD> Added match '" << dbusMatchString << "'\n"; } // Crude 2 second wait to let nxcl get going before we send // the settings. This _must_ be more sophisticated in your // application ;) sleep (2); cout << "NXCMD> Configure session\n"; // We now set up the config data structure. We take user, host // and pass from the command line, but for the sake of // simplicity, we hard-code the rest of the settings here. cfg.serverHost = argv[1]; cfg.serverPort = 22; cfg.sessionUser = argv[2]; cfg.sessionPass = argv[3]; cfg.sessionName = "nxcmd"; cfg.sessionType = argv[4]; cfg.cache = 8; cfg.images = 32; cfg.linkType = "adsl"; cfg.render = true; cfg.backingstore = "when_requested"; cfg.imageCompressionMethod = 2; cfg.imageCompressionLevel = 1; cfg.geometry = "800x600+0+0"; cfg.keyboard = "defkeymap"; cfg.kbtype = "pc105/defkeymap"; cfg.media = false; cfg.agentServer = ""; cfg.agentUser = ""; cfg.agentPass = ""; cfg.cups = 0; cfg.encryption = true; cfg.key = cert; cfg.fullscreen = false; // If true, ignore cfg.geometry. cout << "NXCMD> Sending settings\n"; // ...and then send it on dbus. sendSettings (conn, cfg); cout << "NXCMD> Sent settings\n"; // In real application, we'd now listen on the dbus for a list // of sessions we might be able to re-connect to, or // confirmation that a session is starting. Then we could return. bool done = false; while (false == done) { if (REPLY_REQUIRED == (ret = receiveSession (conn))) { // Need to send back a reply saying which connection // to reconnect. cout << "NXCMD> Please choose a session. 0 for the first, etc.\nT0 to terminate the first, etc\n"; if (cfg.sessionType != "shadow") { cout << "Enter -1 to start a new session\n"; } // Choose 0 for first connection, 1 for next etc, or // <0 for a new connection, even if there are existing // sessions. int connNum = 0; string response; cin >> response; stringstream ss; if (response[0] == 'T') { ss << response.substr(1); ss >> connNum; cout << "NXCMD> Terminating session " << connNum << endl; terminateSession (conn, connNum); } else { ss << response; ss >> connNum; sendReply (conn, connNum); if (connNum < 0) { cout << "NXCMD> Starting new NX session\n"; } else { cout << "NXCMD> Attaching to session " << connNum << endl; } done = true; } } else if (SERVER_CAPACITY == ret) { // Have run out of capacity (licences) on the server. done = true; } else { cout << "NXCMD> Starting new NX session\n"; done = true; } } // wait and block for nxcl process to end before exiting. int status = 0; wait (&status); return 0; } static int sendSettings (DBusConnection *bus, nxcl::NXConfigData& cfg) { cout << "NXCMD> sendSettings called\n"; DBusMessage *message; /* Create a new setting signal on the "org.freenx.nxcl.client" * interface, from the object "/org/freenx/nxcl/dbus/settingSignal". */ message = dbus_message_new_signal ("/org/freenx/nxcl/dbus/settingSignal", dbusSendInterface.c_str(), "sessionConfig"); if (NULL == message) { cerr << "NXCMD> Message Null\n"; return -1; } int media=0, enc=0, fs=0; if (cfg.media == true) { media = 1; } if (cfg.encryption == true) { enc = 1; } if (cfg.fullscreen == true) { fs = 1; } dbus_message_append_args (message, DBUS_TYPE_STRING, &cfg.serverHost, //0 DBUS_TYPE_INT32, &cfg.serverPort, DBUS_TYPE_STRING, &cfg.sessionUser, //2 DBUS_TYPE_STRING, &cfg.sessionPass, DBUS_TYPE_STRING, &cfg.sessionName, //4 DBUS_TYPE_STRING, &cfg.sessionType, DBUS_TYPE_INT32, &cfg.cache, //6 DBUS_TYPE_INT32, &cfg.images, DBUS_TYPE_STRING, &cfg.linkType, //8 DBUS_TYPE_INT32, &cfg.render, DBUS_TYPE_STRING, &cfg.backingstore,//10 DBUS_TYPE_INT32, &cfg.imageCompressionMethod, DBUS_TYPE_INT32, &cfg.imageCompressionLevel, //12 DBUS_TYPE_STRING, &cfg.geometry, DBUS_TYPE_STRING, &cfg.keyboard, //14 DBUS_TYPE_STRING, &cfg.kbtype, DBUS_TYPE_INT32, &media, //16 DBUS_TYPE_STRING, &cfg.agentServer, DBUS_TYPE_STRING, &cfg.agentUser, //18 DBUS_TYPE_STRING, &cfg.agentPass, DBUS_TYPE_INT32, &cfg.cups, //20 DBUS_TYPE_STRING, &cfg.key, DBUS_TYPE_INT32, &enc, //22 DBUS_TYPE_INT32, &fs, DBUS_TYPE_STRING, &cfg.customCommand,//24 DBUS_TYPE_INVALID); /* Send the signal */ if (!dbus_connection_send (bus, message, NULL)) { cerr << "NXCMD> Out Of Memory!\n"; exit(1); } /* Clean up */ dbus_message_unref (message); dbus_connection_flush (bus); return 1; } static int sendReply (DBusConnection *bus, int sessionNum) { DBusMessage *message; DBusMessageIter args; /* Create a new session choice signal on the "org.freenx.nxcl.client" * interface, from the object "/org/freenx/nxcl/dbus/sessionChoice". */ message = dbus_message_new_signal ("/org/freenx/nxcl/dbus/sessionChoice", dbusSendInterface.c_str(), "sessionChoice"); if (NULL == message) { cerr << "NXCMD> Message Null\n"; return -1; } dbus_message_iter_init_append (message, &args); if (!dbus_message_iter_append_basic (&args, DBUS_TYPE_INT32, (const void*)&sessionNum)) { cerr << "NXCMD> Out Of Memory!\n"; exit(1); } /* Send the signal */ if (!dbus_connection_send (bus, message, NULL)) { cerr << "NXCMD> Out Of Memory!\n"; exit(1); } /* Clean up */ dbus_message_unref (message); dbus_connection_flush (bus); return 1; } static int terminateSession (DBusConnection *bus, int sessionNum) { DBusMessage *message; DBusMessageIter args; /* Create a new session choice signal on the "org.freenx.nxcl.client" * interface, from the object "/org/freenx/nxcl/dbus/sessionChoice". */ message = dbus_message_new_signal ("/org/freenx/nxcl/dbus/sessionChoice", dbusSendInterface.c_str(), "terminateSession"); if (NULL == message) { cerr << "NXCMD> Message Null\n"; return -1; } dbus_message_iter_init_append (message, &args); if (!dbus_message_iter_append_basic (&args, DBUS_TYPE_INT32, (const void*)&sessionNum)) { cerr << "NXCMD> Out Of Memory!\n"; exit(1); } /* Send the signal */ if (!dbus_connection_send (bus, message, NULL)) { cerr << "NXCMD> Out Of Memory!\n"; exit(1); } /* Clean up */ dbus_message_unref (message); dbus_connection_flush (bus); return 1; } /* * Wait for and receive a message with available sessions, or a * message saying there are no available sessions */ static int receiveSession (DBusConnection* conn) { DBusMessage * message; DBusMessageIter args; DBusError error; char * parameter = NULL; dbus_int32_t iparam = 0, t = 0; int count = 0; bool sessions_obtained = false; int rtn = 0; stringstream ss; cout << "NXCMD> In receiveSession, listening to " << dbusRecvInterface << "\n"; dbus_error_init (&error); int sessionNum = 0; // loop listening for signals being emitted while (sessions_obtained == false) { if (dbus_error_is_set(&error)) { cerr << "NXCMD> Name Error (" << error.message << ")\n"; dbus_error_free(&error); } count = 0; // non blocking read of the next available message dbus_connection_read_write(conn, 0); message = dbus_connection_pop_message(conn); // loop again if we haven't read a message if (NULL == message) { sleep (1); continue; } // check if the message is a signal from the // correct interface and with the correct name if (dbus_message_is_signal (message, dbusRecvInterface.c_str(), "AvailableSession")) { if (!dbus_message_iter_init (message, &args)) { cerr << "NXCMD> Message has no arguments!\n"; dbus_connection_flush (conn); dbus_message_unref (message); continue; } if (DBUS_TYPE_INT32 != dbus_message_iter_get_arg_type (&args)) { cerr << "NXCMD> First argument is not int32!\n"; } else { dbus_message_iter_get_basic (&args, &iparam); if (sessionNum == 0) { cout << "NXCMD> Available sessions:\n"; } cout << sessionNum++ << ": " << iparam; count++; } // read the parameters - something like: while (dbus_message_iter_next (&args)) { if (DBUS_TYPE_STRING == (t = dbus_message_iter_get_arg_type(&args))) { dbus_message_iter_get_basic(&args, ¶meter); cout << " " << parameter; ss.str(""); ss << parameter; count++; } else if (t == DBUS_TYPE_INT32) { dbus_message_iter_get_basic (&args, &iparam); cout << " " << iparam; ss.str(""); ss << iparam; count++; } else { cerr << "NXCMD> Error, parameter is not string or int.\n"; } // Now we'd do something sensible with the data... } cout << endl; } else if (dbus_message_is_signal (message, dbusRecvInterface.c_str(), "NoMoreAvailable")) { sessions_obtained = true; rtn = REPLY_REQUIRED; } else if (dbus_message_is_signal (message, dbusRecvInterface.c_str(), "Connecting")) { sessions_obtained = true; rtn = NEW_CONNECTION; } else if (dbus_message_is_signal (message, dbusRecvInterface.c_str(), "ServerCapacityReached")) { sessions_obtained = true; rtn = SERVER_CAPACITY; } else { #ifdef DEBUG cout << "NXCMD> None of the above...\n"; if (!dbus_message_iter_init(message, &args)) { cerr << "NXCMD> Message has no arguments!\n"; dbus_connection_flush (conn); dbus_message_unref (message); continue; } if (DBUS_TYPE_STRING == (t = dbus_message_iter_get_arg_type(&args))) { dbus_message_iter_get_basic(&args, ¶meter); cout << "NXCMD> Parameter: " << parameter << endl; } #endif } dbus_connection_flush (conn); dbus_message_unref (message); } // while() return rtn; } nxcl-0.9/nxcl/0000755000175000017500000000000010764221506011745 5ustar mjj29mjj29nxcl-0.9/nxcl/.svn/0000755000175000017500000000000010764221506012631 5ustar mjj29mjj29nxcl-0.9/nxcl/.svn/text-base/0000755000175000017500000000000010764221506014525 5ustar mjj29mjj29nxcl-0.9/nxcl/.svn/text-base/main.cpp.svn-base0000444000175000017500000001044710764221506017676 0ustar mjj29mjj29/*************************************************************************** nxcl: The NXCL dbus daemon. ------------------- begin : June 2007 copyright : (C) 2007 Embedded Software Foundry Ltd. (U.K.) : Author: Sebastian James email : seb@esfnet.co.uk ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ /*! * This program should be launched by a client - that might be * nxlaunch (already written) or (not yet written) qtnxc, fltknxc, * tknxc, emacsnxc.... etc etc you get the picture. * * The graphical launcher program is the place where the user can * select the connection type, and enter his username and password. It * launches nxcl, then transmits the settings to nxcl via dbus. nxcl * then negotiates the NX connection - launching nxssh and * nxproxy. nxcl will send back a list of sessions to the launching * NX client (if there are multiple available sessions) and a signal * to say if the connection has been launched or if an error occurred. */ #include "../config.h" #include "nxclientlib_i18n.h" #include "nxclientlib.h" #include "nxcl.h" #include "nxdata.h" #include /* This define is required for slightly older versions of dbus as * found, for example, in Ubuntu 6.06. */ #define DBUS_API_SUBJECT_TO_CHANGE 1 extern "C" { #include #include } using namespace nxcl; using namespace std; /*! * Log file ofstream is a global variable, as required by nxcl. */ ofstream debugLogFile; /*! * This probing routine is executed on a regular basis. It will set * off suitable signals if there is stdout or stderr to be analysed * from the nxssh process. It also recognises when the nxssh program * has exited. */ bool probeNXCL (NXClientLib* lib); int main (int argc, char **argv) { Nxcl nxcl; debugLogFile.open("/tmp/nxcl.log", ios::out|ios::trunc); if (!debugLogFile.is_open()) { nxcl.callbacks.error ("Odd, couldn't open /tmp/nxcl.log"); } if (argc!=2) { nxcl.callbacks.error ("This program is usually executed by another program. " "Trying to execute it alone is probably not the right " "thing to do, unless you are sure it is. Provide a single " "argument - the identifier for the dbus messages"); return -1; } stringstream ss; int id; ss << argv[1]; ss >> id; nxcl.setupDbus(id); // Send a message to the frontend client to say we are up and running nxcl.callbacks.write (NXCL_ALIVE, _("nxcl is up and running")); if (-1 == (nxcl.receiveSettings())) { cerr << "Failed to obtain server and user for the session." << endl; return -1; } nxcl.callbacks.write (NXCL_STARTING, _("Connection is starting...")); nxcl.startTheNXConnection(); NXClientLib* c = nxcl.getNXClientLib(); while (probeNXCL(c) == true && !c->getSessionRunning()) { usleep (30000); // 3 100ths of a second => about 30 // probes a second. This will impact on power consumption. } // Now the process has started, reduce polling. while (probeNXCL(c) == true) { usleep (2000000); // poll once every 2 seconds. } nxcl.callbacks.write (NXCL_FINISHED, _("Program finished.")); debugLogFile.close(); return 0; } bool probeNXCL (NXClientLib* lib) { notQProcess* p = lib->getNXSSHProcess(); if ((lib->getIsFinished()) == false) { // We need to repeatedly check if there is any output to parse. if (lib->getReadyForProxy() == false) { //p = lib->getNXSSHProcess(); p->probeProcess(); } else { //p = lib->getNXSSHProcess(); p->probeProcess(); p = lib->getNXProxyProcess(); p->probeProcess(); } return true; } else { return false; } } nxcl-0.9/nxcl/.svn/text-base/nxcl.cpp.svn-base0000444000175000017500000004634210764221506017721 0ustar mjj29mjj29/*************************************************************************** nxcl: The NXCL dbus daemon. ------------------- begin : June 2007 copyright : (C) 2007 Embedded Software Foundry Ltd. (U.K.) : Author: Sebastian James email : seb@esfnet.co.uk ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #include "../config.h" #include "nxclientlib_i18n.h" #include "nxclientlib.h" #include #include "nxcl.h" /* This define is required for slightly older versions of dbus as * found, for example, in Ubuntu 6.06. */ #define DBUS_API_SUBJECT_TO_CHANGE 1 extern "C" { #include #include } using namespace nxcl; using namespace std; /*! * NxclCallbacks class */ //@{ NxclCallbacks::NxclCallbacks () { } NxclCallbacks::~NxclCallbacks () { } void NxclCallbacks::write (string msg) { this->parent->sendDbusInfoMsg (msg); } void NxclCallbacks::write (int num, string msg) { this->parent->sendDbusInfoMsg (num, msg); } void NxclCallbacks::error (string msg) { cerr << "NXCL_ERROR> " << msg << endl; this->parent->sendDbusErrorMsg (msg); } void NxclCallbacks::debug (string msg) { #if DEBUG==1 cout << "NXCL_DBG> " << msg << endl; #endif } void NxclCallbacks::stdoutSignal (string msg) { #if DEBUG==1 cout << "nxssh-stdout->" << endl << msg << endl; #endif } void NxclCallbacks::stderrSignal (string msg) { #if DEBUG==1 cout << "nxssh-stderr->" << endl << msg << endl; #endif } void NxclCallbacks::stdinSignal (string msg) { #if DEBUG==1 cout << "nxssh<-stdin-" << endl << msg << endl; #endif } void NxclCallbacks::resumeSessionsSignal (list data) { this->parent->haveResumableSessions (data); } void NxclCallbacks::noSessionsSignal (void) { this->parent->noResumableSessions(); } void NxclCallbacks::serverCapacitySignal (void) { this->parent->serverCapacityReached(); } //@} /*! * Implementation of the Nxcl class, which manages an NX session on * behalf of a calling client, which communicates with this class via * a dbus connection. */ //@{ Nxcl::Nxcl () { this->dbusNum = 0; this->initiate(); } Nxcl::Nxcl (int n) { this->dbusNum = n; this->initiate(); } Nxcl::~Nxcl () { } void Nxcl::initiate (void) { this->setSessionDefaults(); this->nxclientlib.setExternalCallbacks (&callbacks); this->callbacks.setParent (this); // Get the X display information Display* display; display = XOpenDisplay (getenv("DISPLAY")); if (display == NULL) { cerr << "Cannot connect to local X server :0\n"; exit (-1); } int screenNum = DefaultScreen (display); this->xRes = DisplayWidth (display, screenNum); this->yRes = DisplayHeight (display, screenNum); dbgln ("screen is " << xRes << "x" << yRes); unsigned long wp = WhitePixel (display, screenNum); unsigned long bp = BlackPixel (display, screenNum); unsigned long d = wp-bp+1; dbgln ("wp is " << wp << " bp is " << bp << " and difference plus 1 (d) is " << d); this->displayDepth = 0; while (d > 1) { d = d>>1; this->displayDepth++; } dbgln ("displayDepth is " << this->displayDepth << " and d is now " << d); XCloseDisplay (display); } void Nxcl::setupDbus (int id) { this->dbusNum = id; this->setupDbus(); } void Nxcl::setupDbus (void) { /* Get a connection to the session bus */ dbus_error_init (&this->error); this->conn = dbus_bus_get (DBUS_BUS_SESSION, &this->error); if (!this->conn) { cerr << "Failed to connect to the D-BUS daemon: " << this->error.message << ". Exiting.\n"; dbus_error_free (&this->error); exit (1); } stringstream ss; ss << "org.freenx.nxcl.nxcl" << this->dbusNum; this->dbusName = ss.str(); int ret = dbus_bus_request_name(this->conn, this->dbusName.c_str(), DBUS_NAME_FLAG_REPLACE_EXISTING, &this->error); if (dbus_error_is_set(&this->error)) { cerr << "Name Error (" << this->error.message << ")\n"; dbus_error_free(&this->error); } if (DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER != ret) { /* What to do if someone else is running? Try another name? Exit? */ this->callbacks.error ("There appears to be another nxcl running, won't compete. Exiting."); exit(1); } // Done getting connection to session bus // Prepare interface - add a rule for which messages we want // to see. We listen for messages from the _client_ // connection. ss.str(""); ss << "type='signal',interface='org.freenx.nxcl.client" << this->dbusNum << "'"; this->dbusMatch = ss.str(); dbus_bus_add_match(this->conn, this->dbusMatch.c_str(), &this->error); dbus_connection_flush (this->conn); if (dbus_error_is_set(&this->error)) { cerr << "Match Error (" << this->error.message << ")\n"; exit(1); } ss.str(""); ss << "org.freenx.nxcl.client" << this->dbusNum; this->dbusMatchInterface = ss.str(); ss.str(""); ss << "org.freenx.nxcl.nxcl" << this->dbusNum; this->dbusSendInterface = ss.str(); return; } int Nxcl::receiveSettings (void) { DBusMessage * message; DBusMessageIter args; char * parameter = NULL; bool settings_transferred = false; stringstream ss; int count = 0; this->callbacks.debug ("receiveSettings called"); // loop listening for signals being emitted while (settings_transferred == false) { if (dbus_error_is_set(&this->error)) { stringstream errmsg; errmsg << "receiveSettings(): Got a dbus error '" << this->error.name << "': " << this->error.message; this->callbacks.error (errmsg.str()); dbus_error_free (&this->error); } // non blocking read of the next available message dbus_connection_read_write(this->conn, 0); message = dbus_connection_pop_message(this->conn); // loop again if we haven't read a message if (NULL == message) { //this->callbacks.debug ("receiveSettings(): No message yet, sleep a second."); usleep(1000000); continue; } // check if the message is a signal from the // correct interface and with the correct name this->callbacks.debug ("call dbus_message_is_signal()"); if (dbus_message_is_signal (message, this->dbusMatchInterface.c_str(), "sessionConfig")) { if (!dbus_message_iter_init(message, &args)) { cerr << "Message has no arguments!\n"; dbus_connection_flush (conn); dbus_message_unref (message); continue; } if (DBUS_TYPE_STRING != dbus_message_iter_get_arg_type(&args)) { cerr << "First argument is not a string!\n"; } else { dbus_message_iter_get_basic(&args, ¶meter); ss.str(""); ss << parameter; this->nxserver = ss.str(); count++; } // read the rest of the parameters int t; while (dbus_message_iter_next (&args)) { if (DBUS_TYPE_STRING == (t = dbus_message_iter_get_arg_type(&args))) { dbus_message_iter_get_basic(&args, ¶meter); //cout << "Arg-" << count << ": " << parameter << endl; ss.str(""); ss << parameter; switch (count) { case 2: this->nxuser = ss.str(); break; case 3: this->nxpass = ss.str(); break; case 4: this->sessionData.sessionName = ss.str(); break; case 5: this->sessionData.sessionType = ss.str(); break; case 8: this->sessionData.linkType = ss.str(); break; case 10: this->sessionData.backingstore = ss.str(); break; case 13: this->sessionData.geometry = ss.str(); break; case 14: this->sessionData.keyboard = ss.str(); break; case 15: this->sessionData.kbtype = ss.str(); break; case 17: this->sessionData.agentServer = ss.str(); break; case 18: this->sessionData.agentUser = ss.str(); break; case 19: this->sessionData.agentPass = ss.str(); break; case 21: this->sessionData.key = ss.str(); break; case 24: this->sessionData.customCommand = ss.str(); break; default: this->callbacks.error ("ERROR: parameter type does not match its position in the message."); break; } count++; } else if (t == DBUS_TYPE_INT32) { int iparam = 0; dbus_message_iter_get_basic(&args, &iparam); switch (count) { case 1: this->nxport = iparam; break; case 6: this->sessionData.cache = iparam; break; case 7: this->sessionData.images = iparam; break; case 9: this->sessionData.render = (iparam>0) ? true : false; break; case 11: this->sessionData.imageCompressionMethod = iparam; break; case 12: this->sessionData.imageCompressionLevel = iparam; break; case 16: this->sessionData.media = (iparam>0) ? true : false; break; case 20: this->sessionData.cups = iparam; break; case 22: this->sessionData.encryption = (iparam>0) ? true : false; break; case 23: this->sessionData.fullscreen = (iparam>0) ? true : false; break; case 25: this->sessionData.virtualDesktop = (iparam>0) ? true : false; break; default: this->callbacks.error ("ERROR: parameter type does not match its position in the message."); break; } count++; } else { this->callbacks.error ("ERROR: parameter is not string or int."); } } settings_transferred = true; } else { this->callbacks.debug ("this message is not a signal"); } // Anything else required for cleanup? dbus_connection_flush (this->conn); // free the message dbus_message_unref (message); } // while() this->callbacks.debug ("Got the session settings over the dbus\n"); if (this->nxserver.size() == 0 || this->nxuser.size() == 0) { // We need at least these to be able to connect. Leave // nxpass out, in case that has been set to an empty // string. return -1; } else { return 0; } } void Nxcl::setSessionDefaults (void) { // Some defaults this->sessionData.sessionName = "default session"; this->sessionData.sessionType = "unix-gnome"; this->sessionData.cache = 8; this->sessionData.images = 32; this->sessionData.linkType = "adsl"; this->sessionData.render = true; this->sessionData.backingstore = "when_requested"; this->sessionData.imageCompressionMethod = 2; // this->sessionData.imageCompressionLevel; this->sessionData.geometry = "800x600+0+0"; // This'll be the size of the session this->sessionData.keyboard = "defkeymap"; this->sessionData.kbtype = "pc102/defkeymap"; this->sessionData.media = false; this->sessionData.agentServer = ""; this->sessionData.agentUser = ""; this->sessionData.agentPass = ""; this->sessionData.cups = 0; this->sessionData.encryption = true; this->sessionData.suspended = false; this->sessionData.fullscreen = false; // If true, session.geometry // is ignored this->sessionData.virtualDesktop = false; return; } void Nxcl::startTheNXConnection (void) { // First things first; set the sessionData. // FIXME: Should check if this->sessionData has been set. this->nxclientlib.setSessionData (&this->sessionData); this->nxclientlib.setUsername (this->nxuser); this->nxclientlib.setPassword (this->nxpass); // Probe for X display resolution in nxcl. this->nxclientlib.setResolution (this->xRes, this->yRes); // This is the size of // your screen... We need // to set this from the // client, unless we can // probe within nxcl. this->nxclientlib.setDepth (this->displayDepth); // depth gets stored // in NXSession // object. nxcl.setDepth // is a wrapper // around // NXSession's // setDepth method. /* If we have session info, start up the connection */ if (this->sessionData.key.size() == 0) { // Shouldn't need this->sessionData.encryption here. this->callbacks.error (_("No key supplied! Please fix your client to send a key via dbus!")); } else { this->nxclientlib.invokeNXSSH("supplied", this->nxserver, this->sessionData.encryption, this->sessionData.key, this->nxport); } } void Nxcl::haveResumableSessions (list resumable) { this->callbacks.debug ("haveResumableSessions Called"); // Send the list to the calling client: this->sendResumeList (resumable); this->callbacks.debug ("sent the resume list, about to receiveStartInstruction"); // Wait (and block) until we are told whether to resume one of // the sessions or start a new one. this->receiveStartInstruction(); this->callbacks.debug ("receiveStartInstruction() returned."); } void Nxcl::noResumableSessions (void) { this->callbacks.debug ("noResumableSessions Called"); DBusMessage *msg = dbus_message_new_signal ("/org/freenx/nxcl/dbus/AvailableSession", this->dbusSendInterface.c_str(), "Connecting"); dbus_connection_send (this->conn, msg, NULL); dbus_message_unref (msg); } void Nxcl::sendResumeList (list& resumable) { this->callbacks.debug ("sendResumeList called, will send on " + this->dbusSendInterface + " interface"); list::iterator it; for (it=resumable.begin(); it!=resumable.end(); it++) { this->callbacks.debug ("Sending a session.."); DBusMessage *message; /* Create a new signal "AvailableSession" on the * "org.freenx.nxcl.nxcl" interface, from the object * "/org/freenx/nxcl/dbus/AvailableSession". */ message = dbus_message_new_signal ("/org/freenx/nxcl/dbus/AvailableSession", this->dbusSendInterface.c_str(), "AvailableSession"); // We have to create a const char* pointer for each // string variable in the NXResumeSessions struct. const char* sessionType = (*it).sessionType.c_str(); const char* sessionID = (*it).sessionID.c_str(); const char* options = (*it).options.c_str(); const char* screen = (*it).screen.c_str(); const char* available = (*it).available.c_str(); const char* sessionName = (*it).sessionName.c_str(); // Bundle up the available session dbus_message_append_args (message, DBUS_TYPE_INT32, &(*it).display, DBUS_TYPE_STRING, &sessionType, DBUS_TYPE_STRING, &sessionID, DBUS_TYPE_STRING, &options, DBUS_TYPE_INT32, &(*it).depth, DBUS_TYPE_STRING, &screen, DBUS_TYPE_STRING, &available, DBUS_TYPE_STRING, &sessionName, DBUS_TYPE_INVALID); dbus_connection_send (this->conn, message, NULL); dbus_message_unref (message); } DBusMessage *complete = dbus_message_new_signal ("/org/freenx/nxcl/dbus/AvailableSession", this->dbusSendInterface.c_str(), "NoMoreAvailable"); this->callbacks.debug ("About to send the finishup message"); dbus_connection_send (this->conn, complete, NULL); this->callbacks.debug ("Sent the finishup message"); dbus_message_unref (complete); } void Nxcl::serverCapacityReached (void) { DBusMessage *msg = dbus_message_new_signal ("/org/freenx/nxcl/dbus/AvailableSession", this->dbusSendInterface.c_str(), "ServerCapacityReached"); dbus_connection_send (this->conn, msg, NULL); dbus_message_unref (msg); } void Nxcl::sendDbusInfoMsg (string& info) { DBusMessage *msg = dbus_message_new_signal ("/org/freenx/nxcl/dbus/SessionStatus", this->dbusSendInterface.c_str(), "InfoMessage"); /* Add info to msg*/ const char* infoptr = info.c_str(); // Bundle up the available session dbus_message_append_args (msg, DBUS_TYPE_STRING, &infoptr, DBUS_TYPE_INVALID); dbus_connection_send (this->conn, msg, NULL); dbus_message_unref (msg); } void Nxcl::sendDbusInfoMsg (int num, string& info) { DBusMessage *msg = dbus_message_new_signal ("/org/freenx/nxcl/dbus/SessionStatus", this->dbusSendInterface.c_str(), "InfoMessage"); /* Add info to msg*/ const char* infoptr = info.c_str(); // Bundle up the available session dbus_message_append_args (msg, DBUS_TYPE_STRING, &infoptr, DBUS_TYPE_INT32, &num, DBUS_TYPE_INVALID); dbus_connection_send (this->conn, msg, NULL); dbus_message_unref (msg); } void Nxcl::sendDbusErrorMsg (string& errorMsg) { DBusMessage *msg = dbus_message_new_signal ("/org/freenx/nxcl/dbus/SessionStatus", this->dbusSendInterface.c_str(), "ErrorMessage"); /* Add info to msg */ const char* errptr = errorMsg.c_str(); // Bundle up the available session dbus_message_append_args (msg, DBUS_TYPE_STRING, &errptr, DBUS_TYPE_INVALID); dbus_connection_send (this->conn, msg, NULL); dbus_message_unref (msg); } void Nxcl::receiveStartInstruction (void) { DBusMessage * message; DBusMessageIter args; dbus_int32_t parameter = 0; bool instruction_received = false; stringstream ss; this->callbacks.debug ("receiveStartInstruction() called"); // loop listening for signals being emitted while (instruction_received == false) { // non blocking read of the next available message dbus_connection_read_write(this->conn, 0); message = dbus_connection_pop_message(this->conn); // loop again if we haven't read a message if (NULL == message) { usleep(1000000); continue; } // check if the message is a signal from the // correct interface and with the correct name if (dbus_message_is_signal (message, this->dbusMatchInterface.c_str(), "sessionChoice")) { // read the parameters if (!dbus_message_iter_init(message, &args)) cerr << "Message has no arguments!\n"; else if (DBUS_TYPE_INT32 != dbus_message_iter_get_arg_type(&args)) cerr << "Argument is not int32!\n"; else { dbus_message_iter_get_basic(&args, ¶meter); instruction_received = true; if (parameter < 0) { // No action, start a new connection } else { this->nxclientlib.chooseResumable (parameter); } } } else if (dbus_message_is_signal (message, this->dbusMatchInterface.c_str(), "terminateSession")) { // read the parameters if (!dbus_message_iter_init(message, &args)) cerr << "Message has no arguments!\n"; else if (DBUS_TYPE_INT32 != dbus_message_iter_get_arg_type(&args)) cerr << "Argument is not int32!\n"; else { dbus_message_iter_get_basic(&args, ¶meter); ss.str(""); ss << parameter; this->callbacks.debug ("Terminating: " + ss.str()); instruction_received = true; if (parameter < 0) { // No action, start a new connection } else { this->nxclientlib.terminateSession (parameter); } } } dbus_connection_flush (this->conn); dbus_message_unref (message); } } void Nxcl::requestConfirmation (string msg) { this->callbacks.error ("WARNING: requestConfirmation(): This is a placeholder method " "to deal with sending back a yes " "or a no answer. For now, we just set " "this->nxclientlib.getSession().setContinue(true);"); this->nxclientlib.getSession()->setContinue (true); } //@} nxcl-0.9/nxcl/.svn/text-base/Makefile.am.svn-base0000444000175000017500000000067310764221506020302 0ustar mjj29mjj29AM_CPPFLAGS = @PACKAGE_CFLAGS@ -DPACKAGE_DATA_DIR=\""$(datadir)"\" -DLOCALEDIR=\"$(localedir)\" -DPACKAGE_BIN_DIR=\""$(bindir)"\" $(DBUS_CFLAGS) if DEBUG AM_CPPFLAGS += -DDEBUG endif INCLUDES = -I../lib bin_PROGRAMS = nxcl nxcl_SOURCES = main.cpp nxcl.cpp # This links to X11 so that nxcl can obtain the X server's actual screen size nxcl_LDADD = @PACKAGE_LIBS@ $(LIBINTL) $(DBUS_LIBS) -L../lib -lnxcl -lX11 pkginclude_HEADERS = nxcl.h nxcl-0.9/nxcl/.svn/text-base/nxcl.h.svn-base0000444000175000017500000002346010764221506017362 0ustar mjj29mjj29/* -*-c++-*- */ /*************************************************************************** nxcl: The NXCL dbus daemon. ------------------- begin : June 2007 copyright : (C) 2007 Embedded Software Foundry Ltd. (U.K.) : Author: Sebastian James email : seb@esfnet.co.uk ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ /*! * \file nxcl.h This file contains the definition of the Nxcl class * used by the nxcl program. * * See main.cpp for general notes. */ #ifndef _NXCL_H_ #define _NXCL_H_ 1 #include "nxdata.h" #include "../lib/nxclientlib.h" /* This define is required for slightly older versions of dbus as * found, for example, in Ubuntu 6.06. */ #define DBUS_API_SUBJECT_TO_CHANGE 1 extern "C" { #include } using namespace std; namespace nxcl { class NxclBase { public: NxclBase() {} virtual ~NxclBase() {} virtual void haveResumableSessions (list resumeData) {} virtual void noResumableSessions (void) {} virtual void serverCapacityReached (void) {} virtual void sendDbusInfoMsg (string&) {} virtual void sendDbusInfoMsg (int, string&) {} virtual void sendDbusErrorMsg (string&) {} }; class NxclCallbacks : public NXClientLibExternalCallbacks { public: NxclCallbacks (); ~NxclCallbacks (); /*! * Send a message to the user. Here, this is * implemented as a message sent on the dbus interface * * \param msg The message string to be sent */ void write (string msg); /*! * Send a message to the user with a message * number. Here, this is implemented as a message sent * on the dbus interface * * \param num A message number.This is for * transferring the NoMachine NX message number * accompanying the message. This number can be used * by the frontend client to determine the progress of * the session connection. * * \param msg The message string to be sent */ void write (int num, string msg); /*! * Write an error message to stderr. */ void error (string msg); /*! * Send a debugging message out. Here that's * implemented as a message on stdout. */ void debug (string msg); /*! * This is called when some data comes from the stdout * of the nxssh process. This implementation sends a * copy of that data to stdout of nxcl, for debugging * purposes (and only when DEBUG==1, * i.e. --enable-debug-output was given as an option * to the configure script. */ void stdoutSignal (string msg); /*! * Outputs a copy of stderr output from the nxssh * process. */ void stderrSignal (string msg); /*! * Outputs a copy of the stdin input sent to the nxssh * process to the stdout of nxcl for debugging * purposes. */ void stdinSignal (string msg); /*! * Sends the list of resumable sessions (resumeData) * to the client of the nxcl program via a dbus * message. */ void resumeSessionsSignal (list resumeData); /*! * Tells nxcl that there are no suspended sessions and * that connection is proceeding with a new * connection. This fact is sent to the client of nxcl * as a dbus message. */ void noSessionsSignal (void); /*! * This callback sends a message via dbus to the * client of the nxcl program saying "the server has * no more capacity". This basically means that there * are not enough licences to allow the connection, * but it may also occur if there is any sort of RAM * limit checking in nxserver (I don't know if this is * true). */ void serverCapacitySignal (void); /*! * Accessor function to set a pointer to the parent Nxcl object. */ void setParent (NxclBase * p) { this->parent = p; } private: NxclBase * parent; }; class Nxcl : public NxclBase { public: Nxcl(); Nxcl(int n); ~Nxcl(); // Public Methods /*! * \brief Sets up a connection to the dbus daemon, based on * the member attribute \see dbusNum. * * Sets the connection up to listen for messages on * the interface org.freenx.nxcl.clientX where X * starts at 0 and the first available number is taken * (if another nxcl is running with * org.freenx.nxcl.client0, then 1 is * chosen). Messages are sent out on the interface * org.freenx.nxcl.nxclX */ void setupDbus (void); /*! * \brief Sets dbusNum to be \arg id, then calls \see * setupDbus(). * * \param id The number to use to set up the dbus * connection (used as a suffix for interface names). */ void setupDbus (int id); /*! * \brief Wait for a dbus message containing session settings. * * This waits for a dbus signal message called * 'sessionConfig' to come in on the listen interface, * then sets \see sessionData based on its contents. * * \return 0 if settings received ok, -1 if we didn't * receive at least the nxserver host and the nxuser * name. */ int receiveSettings (void); /*! * \brief Set default values for \see sessionData */ void setSessionDefaults (void); /*! * \brief Configure the \see nxclientlib object and * then call its \see invokeSSH method. * * This also calls nxclientlib.setResolution to detect * the size of your screen (that's why nxcl links to X * libraries). */ void startTheNXConnection (void); // Accessors //@{ NXClientLib* getNXClientLib (void) { return &(this->nxclientlib); } //@} // Public Slots //@{ /*! * Called by \see NxclCallbacks::resumeSessionsSignal */ void haveResumableSessions (list resumable); /*! * Called by \see NxclCallbacks::noSessionsSignal */ void noResumableSessions (void); /*! * This _should_ send a dbus message to the client of * nxcl, saying "You've never connected to this * (NX)SSH server before, do you wish to * continue?" * * For now, it just sets * this->nxclientlib.getSession()->setContinue (true); */ void requestConfirmation (string msg); /*! * Called by \see NxclCallbacks::serverCapacitySignal */ void serverCapacityReached (void); /*! * Send an informational status message - these are so * that the frontend client can show the user some * progress information in the UI. */ void sendDbusInfoMsg (string& info); /*! * Send an informational status message - these are so * that the frontend client can show the user some * progress information in the UI. This one includes * the NX message number. */ void sendDbusInfoMsg (int num, string& info); /*! * Send an error message via dbus. */ void sendDbusErrorMsg (string& errorMsg); //@} /*! * Public pointer to the callback functions */ NxclCallbacks callbacks; private: /*! * \brief Set up data structures, determine display height and width. * * This is called by the constructors. */ void initiate (void); /*! * Send the resumable sessions as dbus messages. One * message (called "AvailableSession") is sent for * each resumable session available on the NX * server. When they have all been sent, a message is * sent called "NoMoreAvailable". * * Called by \see haveResumableSessions. * * \param resumable a list of resumable sessions to be * sent on the dbus interface. * */ void sendResumeList (list& resumable); /*! * Wait for a message on the dbus interface to tell us * which of the resumable sessions available on the NX * server we should start. Call * nxclientlib.chooseResumable() or * nxclientlib.terminateSession based on the contents * of the received message. * * Called by \see haveResumableSessions. */ void receiveStartInstruction (void); /*! * The nxclientlib object whose methods will negotiate * the NX session. */ NXClientLib nxclientlib; /*! * We populate this data structure before passing the * information to the nxclientlib object so it can * start up the desired connection. */ NXSessionData sessionData; /*! * The connection to the dbus daemon. */ DBusConnection *conn; /*! * Used when calling dbus functions. */ DBusError error; /*! * Used to make our dbus interfaces unique. This * number is appended to the dbus interface names. */ int dbusNum; /*! * The name to use for our connection to DBUS. */ string dbusName; /*! * Match messages from this DBUS source. */ string dbusMatch; /*! * The DBUS interface which we will listen to. */ string dbusMatchInterface; /*! * The DBUS interface we'll send on. */ string dbusSendInterface; /*! * Holds the username for the connection to the NX * Server. */ string nxuser; /*! * Holds the password for the connection to the NX * Server. */ string nxpass; /*! * Holds the ip/hostname of the NX Server to which we * will try to connect. */ string nxserver; /*! * Holds the port on the NX Server to which we will * try to connect. */ int nxport; /*! * Width of the screen in pixels. */ int xRes; /*! * Height of the screen in pixels. */ int yRes; /*! * Colour depth of the screen. */ int displayDepth; }; } // namespace #endif // ifndef _NXCL_H_ nxcl-0.9/nxcl/.svn/prop-base/0000755000175000017500000000000010764221506014521 5ustar mjj29mjj29nxcl-0.9/nxcl/.svn/props/0000755000175000017500000000000010764221506013774 5ustar mjj29mjj29nxcl-0.9/nxcl/.svn/tmp/0000755000175000017500000000000010764221506013431 5ustar mjj29mjj29nxcl-0.9/nxcl/.svn/tmp/text-base/0000755000175000017500000000000010764221506015325 5ustar mjj29mjj29nxcl-0.9/nxcl/.svn/tmp/prop-base/0000755000175000017500000000000010764221506015321 5ustar mjj29mjj29nxcl-0.9/nxcl/.svn/tmp/props/0000755000175000017500000000000010764221506014574 5ustar mjj29mjj29nxcl-0.9/nxcl/.svn/entries0000444000175000017500000000130610764221506014223 0ustar mjj29mjj298 dir 500 svn://svn.berlios.de/freenx/tags/nxcl-0.9/nxcl svn://svn.berlios.de/freenx 2008-01-30T07:57:35.836436Z 456 gwright svn:special svn:externals svn:needs-lock 80778403-ebee-0310-8e0a-e86a689f3fff main.cpp file 2008-03-07T11:13:10.000000Z d2850da5812349a9d9271e5afc37b374 2007-09-15T22:01:07.421404Z 379 sebjames nxcl.cpp file 2008-03-07T11:13:10.000000Z e7abe8136e2486ba9971353d30689c17 2007-10-16T21:26:15.024274Z 408 sebjames Makefile.am file 2008-03-07T11:13:10.000000Z ee6e89f3389c896b8d8e11bba4c3bab7 2008-01-30T07:57:35.836436Z 456 gwright nxcl.h file 2008-03-07T11:13:10.000000Z ad3dccacbe7a9f61266b65021f55d770 2007-09-13T21:35:33.703849Z 378 sebjames nxcl-0.9/nxcl/.svn/format0000444000175000017500000000000210764221506014032 0ustar mjj29mjj298 nxcl-0.9/nxcl/main.cpp0000644000175000017500000001044710764221506013403 0ustar mjj29mjj29/*************************************************************************** nxcl: The NXCL dbus daemon. ------------------- begin : June 2007 copyright : (C) 2007 Embedded Software Foundry Ltd. (U.K.) : Author: Sebastian James email : seb@esfnet.co.uk ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ /*! * This program should be launched by a client - that might be * nxlaunch (already written) or (not yet written) qtnxc, fltknxc, * tknxc, emacsnxc.... etc etc you get the picture. * * The graphical launcher program is the place where the user can * select the connection type, and enter his username and password. It * launches nxcl, then transmits the settings to nxcl via dbus. nxcl * then negotiates the NX connection - launching nxssh and * nxproxy. nxcl will send back a list of sessions to the launching * NX client (if there are multiple available sessions) and a signal * to say if the connection has been launched or if an error occurred. */ #include "../config.h" #include "nxclientlib_i18n.h" #include "nxclientlib.h" #include "nxcl.h" #include "nxdata.h" #include /* This define is required for slightly older versions of dbus as * found, for example, in Ubuntu 6.06. */ #define DBUS_API_SUBJECT_TO_CHANGE 1 extern "C" { #include #include } using namespace nxcl; using namespace std; /*! * Log file ofstream is a global variable, as required by nxcl. */ ofstream debugLogFile; /*! * This probing routine is executed on a regular basis. It will set * off suitable signals if there is stdout or stderr to be analysed * from the nxssh process. It also recognises when the nxssh program * has exited. */ bool probeNXCL (NXClientLib* lib); int main (int argc, char **argv) { Nxcl nxcl; debugLogFile.open("/tmp/nxcl.log", ios::out|ios::trunc); if (!debugLogFile.is_open()) { nxcl.callbacks.error ("Odd, couldn't open /tmp/nxcl.log"); } if (argc!=2) { nxcl.callbacks.error ("This program is usually executed by another program. " "Trying to execute it alone is probably not the right " "thing to do, unless you are sure it is. Provide a single " "argument - the identifier for the dbus messages"); return -1; } stringstream ss; int id; ss << argv[1]; ss >> id; nxcl.setupDbus(id); // Send a message to the frontend client to say we are up and running nxcl.callbacks.write (NXCL_ALIVE, _("nxcl is up and running")); if (-1 == (nxcl.receiveSettings())) { cerr << "Failed to obtain server and user for the session." << endl; return -1; } nxcl.callbacks.write (NXCL_STARTING, _("Connection is starting...")); nxcl.startTheNXConnection(); NXClientLib* c = nxcl.getNXClientLib(); while (probeNXCL(c) == true && !c->getSessionRunning()) { usleep (30000); // 3 100ths of a second => about 30 // probes a second. This will impact on power consumption. } // Now the process has started, reduce polling. while (probeNXCL(c) == true) { usleep (2000000); // poll once every 2 seconds. } nxcl.callbacks.write (NXCL_FINISHED, _("Program finished.")); debugLogFile.close(); return 0; } bool probeNXCL (NXClientLib* lib) { notQProcess* p = lib->getNXSSHProcess(); if ((lib->getIsFinished()) == false) { // We need to repeatedly check if there is any output to parse. if (lib->getReadyForProxy() == false) { //p = lib->getNXSSHProcess(); p->probeProcess(); } else { //p = lib->getNXSSHProcess(); p->probeProcess(); p = lib->getNXProxyProcess(); p->probeProcess(); } return true; } else { return false; } } nxcl-0.9/nxcl/nxcl.cpp0000644000175000017500000004634210764221506013426 0ustar mjj29mjj29/*************************************************************************** nxcl: The NXCL dbus daemon. ------------------- begin : June 2007 copyright : (C) 2007 Embedded Software Foundry Ltd. (U.K.) : Author: Sebastian James email : seb@esfnet.co.uk ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #include "../config.h" #include "nxclientlib_i18n.h" #include "nxclientlib.h" #include #include "nxcl.h" /* This define is required for slightly older versions of dbus as * found, for example, in Ubuntu 6.06. */ #define DBUS_API_SUBJECT_TO_CHANGE 1 extern "C" { #include #include } using namespace nxcl; using namespace std; /*! * NxclCallbacks class */ //@{ NxclCallbacks::NxclCallbacks () { } NxclCallbacks::~NxclCallbacks () { } void NxclCallbacks::write (string msg) { this->parent->sendDbusInfoMsg (msg); } void NxclCallbacks::write (int num, string msg) { this->parent->sendDbusInfoMsg (num, msg); } void NxclCallbacks::error (string msg) { cerr << "NXCL_ERROR> " << msg << endl; this->parent->sendDbusErrorMsg (msg); } void NxclCallbacks::debug (string msg) { #if DEBUG==1 cout << "NXCL_DBG> " << msg << endl; #endif } void NxclCallbacks::stdoutSignal (string msg) { #if DEBUG==1 cout << "nxssh-stdout->" << endl << msg << endl; #endif } void NxclCallbacks::stderrSignal (string msg) { #if DEBUG==1 cout << "nxssh-stderr->" << endl << msg << endl; #endif } void NxclCallbacks::stdinSignal (string msg) { #if DEBUG==1 cout << "nxssh<-stdin-" << endl << msg << endl; #endif } void NxclCallbacks::resumeSessionsSignal (list data) { this->parent->haveResumableSessions (data); } void NxclCallbacks::noSessionsSignal (void) { this->parent->noResumableSessions(); } void NxclCallbacks::serverCapacitySignal (void) { this->parent->serverCapacityReached(); } //@} /*! * Implementation of the Nxcl class, which manages an NX session on * behalf of a calling client, which communicates with this class via * a dbus connection. */ //@{ Nxcl::Nxcl () { this->dbusNum = 0; this->initiate(); } Nxcl::Nxcl (int n) { this->dbusNum = n; this->initiate(); } Nxcl::~Nxcl () { } void Nxcl::initiate (void) { this->setSessionDefaults(); this->nxclientlib.setExternalCallbacks (&callbacks); this->callbacks.setParent (this); // Get the X display information Display* display; display = XOpenDisplay (getenv("DISPLAY")); if (display == NULL) { cerr << "Cannot connect to local X server :0\n"; exit (-1); } int screenNum = DefaultScreen (display); this->xRes = DisplayWidth (display, screenNum); this->yRes = DisplayHeight (display, screenNum); dbgln ("screen is " << xRes << "x" << yRes); unsigned long wp = WhitePixel (display, screenNum); unsigned long bp = BlackPixel (display, screenNum); unsigned long d = wp-bp+1; dbgln ("wp is " << wp << " bp is " << bp << " and difference plus 1 (d) is " << d); this->displayDepth = 0; while (d > 1) { d = d>>1; this->displayDepth++; } dbgln ("displayDepth is " << this->displayDepth << " and d is now " << d); XCloseDisplay (display); } void Nxcl::setupDbus (int id) { this->dbusNum = id; this->setupDbus(); } void Nxcl::setupDbus (void) { /* Get a connection to the session bus */ dbus_error_init (&this->error); this->conn = dbus_bus_get (DBUS_BUS_SESSION, &this->error); if (!this->conn) { cerr << "Failed to connect to the D-BUS daemon: " << this->error.message << ". Exiting.\n"; dbus_error_free (&this->error); exit (1); } stringstream ss; ss << "org.freenx.nxcl.nxcl" << this->dbusNum; this->dbusName = ss.str(); int ret = dbus_bus_request_name(this->conn, this->dbusName.c_str(), DBUS_NAME_FLAG_REPLACE_EXISTING, &this->error); if (dbus_error_is_set(&this->error)) { cerr << "Name Error (" << this->error.message << ")\n"; dbus_error_free(&this->error); } if (DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER != ret) { /* What to do if someone else is running? Try another name? Exit? */ this->callbacks.error ("There appears to be another nxcl running, won't compete. Exiting."); exit(1); } // Done getting connection to session bus // Prepare interface - add a rule for which messages we want // to see. We listen for messages from the _client_ // connection. ss.str(""); ss << "type='signal',interface='org.freenx.nxcl.client" << this->dbusNum << "'"; this->dbusMatch = ss.str(); dbus_bus_add_match(this->conn, this->dbusMatch.c_str(), &this->error); dbus_connection_flush (this->conn); if (dbus_error_is_set(&this->error)) { cerr << "Match Error (" << this->error.message << ")\n"; exit(1); } ss.str(""); ss << "org.freenx.nxcl.client" << this->dbusNum; this->dbusMatchInterface = ss.str(); ss.str(""); ss << "org.freenx.nxcl.nxcl" << this->dbusNum; this->dbusSendInterface = ss.str(); return; } int Nxcl::receiveSettings (void) { DBusMessage * message; DBusMessageIter args; char * parameter = NULL; bool settings_transferred = false; stringstream ss; int count = 0; this->callbacks.debug ("receiveSettings called"); // loop listening for signals being emitted while (settings_transferred == false) { if (dbus_error_is_set(&this->error)) { stringstream errmsg; errmsg << "receiveSettings(): Got a dbus error '" << this->error.name << "': " << this->error.message; this->callbacks.error (errmsg.str()); dbus_error_free (&this->error); } // non blocking read of the next available message dbus_connection_read_write(this->conn, 0); message = dbus_connection_pop_message(this->conn); // loop again if we haven't read a message if (NULL == message) { //this->callbacks.debug ("receiveSettings(): No message yet, sleep a second."); usleep(1000000); continue; } // check if the message is a signal from the // correct interface and with the correct name this->callbacks.debug ("call dbus_message_is_signal()"); if (dbus_message_is_signal (message, this->dbusMatchInterface.c_str(), "sessionConfig")) { if (!dbus_message_iter_init(message, &args)) { cerr << "Message has no arguments!\n"; dbus_connection_flush (conn); dbus_message_unref (message); continue; } if (DBUS_TYPE_STRING != dbus_message_iter_get_arg_type(&args)) { cerr << "First argument is not a string!\n"; } else { dbus_message_iter_get_basic(&args, ¶meter); ss.str(""); ss << parameter; this->nxserver = ss.str(); count++; } // read the rest of the parameters int t; while (dbus_message_iter_next (&args)) { if (DBUS_TYPE_STRING == (t = dbus_message_iter_get_arg_type(&args))) { dbus_message_iter_get_basic(&args, ¶meter); //cout << "Arg-" << count << ": " << parameter << endl; ss.str(""); ss << parameter; switch (count) { case 2: this->nxuser = ss.str(); break; case 3: this->nxpass = ss.str(); break; case 4: this->sessionData.sessionName = ss.str(); break; case 5: this->sessionData.sessionType = ss.str(); break; case 8: this->sessionData.linkType = ss.str(); break; case 10: this->sessionData.backingstore = ss.str(); break; case 13: this->sessionData.geometry = ss.str(); break; case 14: this->sessionData.keyboard = ss.str(); break; case 15: this->sessionData.kbtype = ss.str(); break; case 17: this->sessionData.agentServer = ss.str(); break; case 18: this->sessionData.agentUser = ss.str(); break; case 19: this->sessionData.agentPass = ss.str(); break; case 21: this->sessionData.key = ss.str(); break; case 24: this->sessionData.customCommand = ss.str(); break; default: this->callbacks.error ("ERROR: parameter type does not match its position in the message."); break; } count++; } else if (t == DBUS_TYPE_INT32) { int iparam = 0; dbus_message_iter_get_basic(&args, &iparam); switch (count) { case 1: this->nxport = iparam; break; case 6: this->sessionData.cache = iparam; break; case 7: this->sessionData.images = iparam; break; case 9: this->sessionData.render = (iparam>0) ? true : false; break; case 11: this->sessionData.imageCompressionMethod = iparam; break; case 12: this->sessionData.imageCompressionLevel = iparam; break; case 16: this->sessionData.media = (iparam>0) ? true : false; break; case 20: this->sessionData.cups = iparam; break; case 22: this->sessionData.encryption = (iparam>0) ? true : false; break; case 23: this->sessionData.fullscreen = (iparam>0) ? true : false; break; case 25: this->sessionData.virtualDesktop = (iparam>0) ? true : false; break; default: this->callbacks.error ("ERROR: parameter type does not match its position in the message."); break; } count++; } else { this->callbacks.error ("ERROR: parameter is not string or int."); } } settings_transferred = true; } else { this->callbacks.debug ("this message is not a signal"); } // Anything else required for cleanup? dbus_connection_flush (this->conn); // free the message dbus_message_unref (message); } // while() this->callbacks.debug ("Got the session settings over the dbus\n"); if (this->nxserver.size() == 0 || this->nxuser.size() == 0) { // We need at least these to be able to connect. Leave // nxpass out, in case that has been set to an empty // string. return -1; } else { return 0; } } void Nxcl::setSessionDefaults (void) { // Some defaults this->sessionData.sessionName = "default session"; this->sessionData.sessionType = "unix-gnome"; this->sessionData.cache = 8; this->sessionData.images = 32; this->sessionData.linkType = "adsl"; this->sessionData.render = true; this->sessionData.backingstore = "when_requested"; this->sessionData.imageCompressionMethod = 2; // this->sessionData.imageCompressionLevel; this->sessionData.geometry = "800x600+0+0"; // This'll be the size of the session this->sessionData.keyboard = "defkeymap"; this->sessionData.kbtype = "pc102/defkeymap"; this->sessionData.media = false; this->sessionData.agentServer = ""; this->sessionData.agentUser = ""; this->sessionData.agentPass = ""; this->sessionData.cups = 0; this->sessionData.encryption = true; this->sessionData.suspended = false; this->sessionData.fullscreen = false; // If true, session.geometry // is ignored this->sessionData.virtualDesktop = false; return; } void Nxcl::startTheNXConnection (void) { // First things first; set the sessionData. // FIXME: Should check if this->sessionData has been set. this->nxclientlib.setSessionData (&this->sessionData); this->nxclientlib.setUsername (this->nxuser); this->nxclientlib.setPassword (this->nxpass); // Probe for X display resolution in nxcl. this->nxclientlib.setResolution (this->xRes, this->yRes); // This is the size of // your screen... We need // to set this from the // client, unless we can // probe within nxcl. this->nxclientlib.setDepth (this->displayDepth); // depth gets stored // in NXSession // object. nxcl.setDepth // is a wrapper // around // NXSession's // setDepth method. /* If we have session info, start up the connection */ if (this->sessionData.key.size() == 0) { // Shouldn't need this->sessionData.encryption here. this->callbacks.error (_("No key supplied! Please fix your client to send a key via dbus!")); } else { this->nxclientlib.invokeNXSSH("supplied", this->nxserver, this->sessionData.encryption, this->sessionData.key, this->nxport); } } void Nxcl::haveResumableSessions (list resumable) { this->callbacks.debug ("haveResumableSessions Called"); // Send the list to the calling client: this->sendResumeList (resumable); this->callbacks.debug ("sent the resume list, about to receiveStartInstruction"); // Wait (and block) until we are told whether to resume one of // the sessions or start a new one. this->receiveStartInstruction(); this->callbacks.debug ("receiveStartInstruction() returned."); } void Nxcl::noResumableSessions (void) { this->callbacks.debug ("noResumableSessions Called"); DBusMessage *msg = dbus_message_new_signal ("/org/freenx/nxcl/dbus/AvailableSession", this->dbusSendInterface.c_str(), "Connecting"); dbus_connection_send (this->conn, msg, NULL); dbus_message_unref (msg); } void Nxcl::sendResumeList (list& resumable) { this->callbacks.debug ("sendResumeList called, will send on " + this->dbusSendInterface + " interface"); list::iterator it; for (it=resumable.begin(); it!=resumable.end(); it++) { this->callbacks.debug ("Sending a session.."); DBusMessage *message; /* Create a new signal "AvailableSession" on the * "org.freenx.nxcl.nxcl" interface, from the object * "/org/freenx/nxcl/dbus/AvailableSession". */ message = dbus_message_new_signal ("/org/freenx/nxcl/dbus/AvailableSession", this->dbusSendInterface.c_str(), "AvailableSession"); // We have to create a const char* pointer for each // string variable in the NXResumeSessions struct. const char* sessionType = (*it).sessionType.c_str(); const char* sessionID = (*it).sessionID.c_str(); const char* options = (*it).options.c_str(); const char* screen = (*it).screen.c_str(); const char* available = (*it).available.c_str(); const char* sessionName = (*it).sessionName.c_str(); // Bundle up the available session dbus_message_append_args (message, DBUS_TYPE_INT32, &(*it).display, DBUS_TYPE_STRING, &sessionType, DBUS_TYPE_STRING, &sessionID, DBUS_TYPE_STRING, &options, DBUS_TYPE_INT32, &(*it).depth, DBUS_TYPE_STRING, &screen, DBUS_TYPE_STRING, &available, DBUS_TYPE_STRING, &sessionName, DBUS_TYPE_INVALID); dbus_connection_send (this->conn, message, NULL); dbus_message_unref (message); } DBusMessage *complete = dbus_message_new_signal ("/org/freenx/nxcl/dbus/AvailableSession", this->dbusSendInterface.c_str(), "NoMoreAvailable"); this->callbacks.debug ("About to send the finishup message"); dbus_connection_send (this->conn, complete, NULL); this->callbacks.debug ("Sent the finishup message"); dbus_message_unref (complete); } void Nxcl::serverCapacityReached (void) { DBusMessage *msg = dbus_message_new_signal ("/org/freenx/nxcl/dbus/AvailableSession", this->dbusSendInterface.c_str(), "ServerCapacityReached"); dbus_connection_send (this->conn, msg, NULL); dbus_message_unref (msg); } void Nxcl::sendDbusInfoMsg (string& info) { DBusMessage *msg = dbus_message_new_signal ("/org/freenx/nxcl/dbus/SessionStatus", this->dbusSendInterface.c_str(), "InfoMessage"); /* Add info to msg*/ const char* infoptr = info.c_str(); // Bundle up the available session dbus_message_append_args (msg, DBUS_TYPE_STRING, &infoptr, DBUS_TYPE_INVALID); dbus_connection_send (this->conn, msg, NULL); dbus_message_unref (msg); } void Nxcl::sendDbusInfoMsg (int num, string& info) { DBusMessage *msg = dbus_message_new_signal ("/org/freenx/nxcl/dbus/SessionStatus", this->dbusSendInterface.c_str(), "InfoMessage"); /* Add info to msg*/ const char* infoptr = info.c_str(); // Bundle up the available session dbus_message_append_args (msg, DBUS_TYPE_STRING, &infoptr, DBUS_TYPE_INT32, &num, DBUS_TYPE_INVALID); dbus_connection_send (this->conn, msg, NULL); dbus_message_unref (msg); } void Nxcl::sendDbusErrorMsg (string& errorMsg) { DBusMessage *msg = dbus_message_new_signal ("/org/freenx/nxcl/dbus/SessionStatus", this->dbusSendInterface.c_str(), "ErrorMessage"); /* Add info to msg */ const char* errptr = errorMsg.c_str(); // Bundle up the available session dbus_message_append_args (msg, DBUS_TYPE_STRING, &errptr, DBUS_TYPE_INVALID); dbus_connection_send (this->conn, msg, NULL); dbus_message_unref (msg); } void Nxcl::receiveStartInstruction (void) { DBusMessage * message; DBusMessageIter args; dbus_int32_t parameter = 0; bool instruction_received = false; stringstream ss; this->callbacks.debug ("receiveStartInstruction() called"); // loop listening for signals being emitted while (instruction_received == false) { // non blocking read of the next available message dbus_connection_read_write(this->conn, 0); message = dbus_connection_pop_message(this->conn); // loop again if we haven't read a message if (NULL == message) { usleep(1000000); continue; } // check if the message is a signal from the // correct interface and with the correct name if (dbus_message_is_signal (message, this->dbusMatchInterface.c_str(), "sessionChoice")) { // read the parameters if (!dbus_message_iter_init(message, &args)) cerr << "Message has no arguments!\n"; else if (DBUS_TYPE_INT32 != dbus_message_iter_get_arg_type(&args)) cerr << "Argument is not int32!\n"; else { dbus_message_iter_get_basic(&args, ¶meter); instruction_received = true; if (parameter < 0) { // No action, start a new connection } else { this->nxclientlib.chooseResumable (parameter); } } } else if (dbus_message_is_signal (message, this->dbusMatchInterface.c_str(), "terminateSession")) { // read the parameters if (!dbus_message_iter_init(message, &args)) cerr << "Message has no arguments!\n"; else if (DBUS_TYPE_INT32 != dbus_message_iter_get_arg_type(&args)) cerr << "Argument is not int32!\n"; else { dbus_message_iter_get_basic(&args, ¶meter); ss.str(""); ss << parameter; this->callbacks.debug ("Terminating: " + ss.str()); instruction_received = true; if (parameter < 0) { // No action, start a new connection } else { this->nxclientlib.terminateSession (parameter); } } } dbus_connection_flush (this->conn); dbus_message_unref (message); } } void Nxcl::requestConfirmation (string msg) { this->callbacks.error ("WARNING: requestConfirmation(): This is a placeholder method " "to deal with sending back a yes " "or a no answer. For now, we just set " "this->nxclientlib.getSession().setContinue(true);"); this->nxclientlib.getSession()->setContinue (true); } //@} nxcl-0.9/nxcl/Makefile.am0000644000175000017500000000067310764221506014007 0ustar mjj29mjj29AM_CPPFLAGS = @PACKAGE_CFLAGS@ -DPACKAGE_DATA_DIR=\""$(datadir)"\" -DLOCALEDIR=\"$(localedir)\" -DPACKAGE_BIN_DIR=\""$(bindir)"\" $(DBUS_CFLAGS) if DEBUG AM_CPPFLAGS += -DDEBUG endif INCLUDES = -I../lib bin_PROGRAMS = nxcl nxcl_SOURCES = main.cpp nxcl.cpp # This links to X11 so that nxcl can obtain the X server's actual screen size nxcl_LDADD = @PACKAGE_LIBS@ $(LIBINTL) $(DBUS_LIBS) -L../lib -lnxcl -lX11 pkginclude_HEADERS = nxcl.h nxcl-0.9/nxcl/nxcl.h0000644000175000017500000002346010764221506013067 0ustar mjj29mjj29/* -*-c++-*- */ /*************************************************************************** nxcl: The NXCL dbus daemon. ------------------- begin : June 2007 copyright : (C) 2007 Embedded Software Foundry Ltd. (U.K.) : Author: Sebastian James email : seb@esfnet.co.uk ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ /*! * \file nxcl.h This file contains the definition of the Nxcl class * used by the nxcl program. * * See main.cpp for general notes. */ #ifndef _NXCL_H_ #define _NXCL_H_ 1 #include "nxdata.h" #include "../lib/nxclientlib.h" /* This define is required for slightly older versions of dbus as * found, for example, in Ubuntu 6.06. */ #define DBUS_API_SUBJECT_TO_CHANGE 1 extern "C" { #include } using namespace std; namespace nxcl { class NxclBase { public: NxclBase() {} virtual ~NxclBase() {} virtual void haveResumableSessions (list resumeData) {} virtual void noResumableSessions (void) {} virtual void serverCapacityReached (void) {} virtual void sendDbusInfoMsg (string&) {} virtual void sendDbusInfoMsg (int, string&) {} virtual void sendDbusErrorMsg (string&) {} }; class NxclCallbacks : public NXClientLibExternalCallbacks { public: NxclCallbacks (); ~NxclCallbacks (); /*! * Send a message to the user. Here, this is * implemented as a message sent on the dbus interface * * \param msg The message string to be sent */ void write (string msg); /*! * Send a message to the user with a message * number. Here, this is implemented as a message sent * on the dbus interface * * \param num A message number.This is for * transferring the NoMachine NX message number * accompanying the message. This number can be used * by the frontend client to determine the progress of * the session connection. * * \param msg The message string to be sent */ void write (int num, string msg); /*! * Write an error message to stderr. */ void error (string msg); /*! * Send a debugging message out. Here that's * implemented as a message on stdout. */ void debug (string msg); /*! * This is called when some data comes from the stdout * of the nxssh process. This implementation sends a * copy of that data to stdout of nxcl, for debugging * purposes (and only when DEBUG==1, * i.e. --enable-debug-output was given as an option * to the configure script. */ void stdoutSignal (string msg); /*! * Outputs a copy of stderr output from the nxssh * process. */ void stderrSignal (string msg); /*! * Outputs a copy of the stdin input sent to the nxssh * process to the stdout of nxcl for debugging * purposes. */ void stdinSignal (string msg); /*! * Sends the list of resumable sessions (resumeData) * to the client of the nxcl program via a dbus * message. */ void resumeSessionsSignal (list resumeData); /*! * Tells nxcl that there are no suspended sessions and * that connection is proceeding with a new * connection. This fact is sent to the client of nxcl * as a dbus message. */ void noSessionsSignal (void); /*! * This callback sends a message via dbus to the * client of the nxcl program saying "the server has * no more capacity". This basically means that there * are not enough licences to allow the connection, * but it may also occur if there is any sort of RAM * limit checking in nxserver (I don't know if this is * true). */ void serverCapacitySignal (void); /*! * Accessor function to set a pointer to the parent Nxcl object. */ void setParent (NxclBase * p) { this->parent = p; } private: NxclBase * parent; }; class Nxcl : public NxclBase { public: Nxcl(); Nxcl(int n); ~Nxcl(); // Public Methods /*! * \brief Sets up a connection to the dbus daemon, based on * the member attribute \see dbusNum. * * Sets the connection up to listen for messages on * the interface org.freenx.nxcl.clientX where X * starts at 0 and the first available number is taken * (if another nxcl is running with * org.freenx.nxcl.client0, then 1 is * chosen). Messages are sent out on the interface * org.freenx.nxcl.nxclX */ void setupDbus (void); /*! * \brief Sets dbusNum to be \arg id, then calls \see * setupDbus(). * * \param id The number to use to set up the dbus * connection (used as a suffix for interface names). */ void setupDbus (int id); /*! * \brief Wait for a dbus message containing session settings. * * This waits for a dbus signal message called * 'sessionConfig' to come in on the listen interface, * then sets \see sessionData based on its contents. * * \return 0 if settings received ok, -1 if we didn't * receive at least the nxserver host and the nxuser * name. */ int receiveSettings (void); /*! * \brief Set default values for \see sessionData */ void setSessionDefaults (void); /*! * \brief Configure the \see nxclientlib object and * then call its \see invokeSSH method. * * This also calls nxclientlib.setResolution to detect * the size of your screen (that's why nxcl links to X * libraries). */ void startTheNXConnection (void); // Accessors //@{ NXClientLib* getNXClientLib (void) { return &(this->nxclientlib); } //@} // Public Slots //@{ /*! * Called by \see NxclCallbacks::resumeSessionsSignal */ void haveResumableSessions (list resumable); /*! * Called by \see NxclCallbacks::noSessionsSignal */ void noResumableSessions (void); /*! * This _should_ send a dbus message to the client of * nxcl, saying "You've never connected to this * (NX)SSH server before, do you wish to * continue?" * * For now, it just sets * this->nxclientlib.getSession()->setContinue (true); */ void requestConfirmation (string msg); /*! * Called by \see NxclCallbacks::serverCapacitySignal */ void serverCapacityReached (void); /*! * Send an informational status message - these are so * that the frontend client can show the user some * progress information in the UI. */ void sendDbusInfoMsg (string& info); /*! * Send an informational status message - these are so * that the frontend client can show the user some * progress information in the UI. This one includes * the NX message number. */ void sendDbusInfoMsg (int num, string& info); /*! * Send an error message via dbus. */ void sendDbusErrorMsg (string& errorMsg); //@} /*! * Public pointer to the callback functions */ NxclCallbacks callbacks; private: /*! * \brief Set up data structures, determine display height and width. * * This is called by the constructors. */ void initiate (void); /*! * Send the resumable sessions as dbus messages. One * message (called "AvailableSession") is sent for * each resumable session available on the NX * server. When they have all been sent, a message is * sent called "NoMoreAvailable". * * Called by \see haveResumableSessions. * * \param resumable a list of resumable sessions to be * sent on the dbus interface. * */ void sendResumeList (list& resumable); /*! * Wait for a message on the dbus interface to tell us * which of the resumable sessions available on the NX * server we should start. Call * nxclientlib.chooseResumable() or * nxclientlib.terminateSession based on the contents * of the received message. * * Called by \see haveResumableSessions. */ void receiveStartInstruction (void); /*! * The nxclientlib object whose methods will negotiate * the NX session. */ NXClientLib nxclientlib; /*! * We populate this data structure before passing the * information to the nxclientlib object so it can * start up the desired connection. */ NXSessionData sessionData; /*! * The connection to the dbus daemon. */ DBusConnection *conn; /*! * Used when calling dbus functions. */ DBusError error; /*! * Used to make our dbus interfaces unique. This * number is appended to the dbus interface names. */ int dbusNum; /*! * The name to use for our connection to DBUS. */ string dbusName; /*! * Match messages from this DBUS source. */ string dbusMatch; /*! * The DBUS interface which we will listen to. */ string dbusMatchInterface; /*! * The DBUS interface we'll send on. */ string dbusSendInterface; /*! * Holds the username for the connection to the NX * Server. */ string nxuser; /*! * Holds the password for the connection to the NX * Server. */ string nxpass; /*! * Holds the ip/hostname of the NX Server to which we * will try to connect. */ string nxserver; /*! * Holds the port on the NX Server to which we will * try to connect. */ int nxport; /*! * Width of the screen in pixels. */ int xRes; /*! * Height of the screen in pixels. */ int yRes; /*! * Colour depth of the screen. */ int displayDepth; }; } // namespace #endif // ifndef _NXCL_H_ nxcl-0.9/doc/0000755000175000017500000000000010764221506011546 5ustar mjj29mjj29nxcl-0.9/doc/.svn/0000755000175000017500000000000010764221506012432 5ustar mjj29mjj29nxcl-0.9/doc/.svn/text-base/0000755000175000017500000000000010764221506014326 5ustar mjj29mjj29nxcl-0.9/doc/.svn/text-base/Doxyfile.svn-base0000444000175000017500000001747410764221506017564 0ustar mjj29mjj29# Doxyfile 1.3.6 #--------------------------------------------------------------------------- # Project related configuration options #--------------------------------------------------------------------------- PROJECT_NAME = nxcl PROJECT_NUMBER = @VERSION@ OUTPUT_DIRECTORY = OUTPUT_LANGUAGE = English USE_WINDOWS_ENCODING = NO BRIEF_MEMBER_DESC = YES REPEAT_BRIEF = YES ABBREVIATE_BRIEF = ALWAYS_DETAILED_SEC = NO INLINE_INHERITED_MEMB = NO FULL_PATH_NAMES = NO STRIP_FROM_PATH = SHORT_NAMES = NO JAVADOC_AUTOBRIEF = NO MULTILINE_CPP_IS_BRIEF = NO DETAILS_AT_TOP = NO INHERIT_DOCS = YES DISTRIBUTE_GROUP_DOC = NO TAB_SIZE = 8 ALIASES = OPTIMIZE_OUTPUT_FOR_C = NO OPTIMIZE_OUTPUT_JAVA = NO SUBGROUPING = YES #--------------------------------------------------------------------------- # Build related configuration options #--------------------------------------------------------------------------- EXTRACT_ALL = NO EXTRACT_PRIVATE = NO EXTRACT_STATIC = NO EXTRACT_LOCAL_CLASSES = YES HIDE_UNDOC_MEMBERS = NO HIDE_UNDOC_CLASSES = NO HIDE_FRIEND_COMPOUNDS = NO HIDE_IN_BODY_DOCS = NO INTERNAL_DOCS = NO CASE_SENSE_NAMES = YES HIDE_SCOPE_NAMES = NO SHOW_INCLUDE_FILES = YES INLINE_INFO = YES SORT_MEMBER_DOCS = YES SORT_BRIEF_DOCS = NO SORT_BY_SCOPE_NAME = NO GENERATE_TODOLIST = YES GENERATE_TESTLIST = YES GENERATE_BUGLIST = YES GENERATE_DEPRECATEDLIST= YES ENABLED_SECTIONS = MAX_INITIALIZER_LINES = 30 SHOW_USED_FILES = YES #--------------------------------------------------------------------------- # configuration options related to warning and progress messages #--------------------------------------------------------------------------- QUIET = NO WARNINGS = YES WARN_IF_UNDOCUMENTED = YES WARN_IF_DOC_ERROR = YES WARN_FORMAT = "$file:$line: $text" WARN_LOGFILE = #--------------------------------------------------------------------------- # configuration options related to the input files #--------------------------------------------------------------------------- INPUT = .. ../nxcl ../lib ../test FILE_PATTERNS = *.h RECURSIVE = NO EXCLUDE = EXCLUDE_SYMLINKS = NO EXCLUDE_PATTERNS = EXAMPLE_PATH = EXAMPLE_PATTERNS = EXAMPLE_RECURSIVE = NO IMAGE_PATH = images INPUT_FILTER = FILTER_SOURCE_FILES = NO #--------------------------------------------------------------------------- # configuration options related to source browsing #--------------------------------------------------------------------------- SOURCE_BROWSER = YES INLINE_SOURCES = NO STRIP_CODE_COMMENTS = YES REFERENCED_BY_RELATION = YES REFERENCES_RELATION = YES VERBATIM_HEADERS = YES #--------------------------------------------------------------------------- # configuration options related to the alphabetical class index #--------------------------------------------------------------------------- ALPHABETICAL_INDEX = NO COLS_IN_ALPHA_INDEX = 4 IGNORE_PREFIX = #--------------------------------------------------------------------------- # configuration options related to the HTML output #--------------------------------------------------------------------------- GENERATE_HTML = YES HTML_OUTPUT = html HTML_FILE_EXTENSION = .html HTML_HEADER = HTML_FOOTER = HTML_STYLESHEET = HTML_ALIGN_MEMBERS = YES GENERATE_HTMLHELP = NO CHM_FILE = HHC_LOCATION = GENERATE_CHI = NO BINARY_TOC = NO TOC_EXPAND = NO DISABLE_INDEX = NO ENUM_VALUES_PER_LINE = 4 GENERATE_TREEVIEW = NO TREEVIEW_WIDTH = 250 #--------------------------------------------------------------------------- # configuration options related to the LaTeX output #--------------------------------------------------------------------------- GENERATE_LATEX = NO LATEX_OUTPUT = latex LATEX_CMD_NAME = latex MAKEINDEX_CMD_NAME = makeindex COMPACT_LATEX = NO PAPER_TYPE = a4wide EXTRA_PACKAGES = LATEX_HEADER = PDF_HYPERLINKS = NO USE_PDFLATEX = NO LATEX_BATCHMODE = NO LATEX_HIDE_INDICES = NO #--------------------------------------------------------------------------- # configuration options related to the RTF output #--------------------------------------------------------------------------- GENERATE_RTF = NO RTF_OUTPUT = rtf COMPACT_RTF = NO RTF_HYPERLINKS = NO RTF_STYLESHEET_FILE = RTF_EXTENSIONS_FILE = #--------------------------------------------------------------------------- # configuration options related to the man page output #--------------------------------------------------------------------------- GENERATE_MAN = NO MAN_OUTPUT = man MAN_EXTENSION = .3 MAN_LINKS = NO #--------------------------------------------------------------------------- # configuration options related to the XML output #--------------------------------------------------------------------------- GENERATE_XML = NO XML_OUTPUT = xml XML_SCHEMA = XML_DTD = XML_PROGRAMLISTING = YES #--------------------------------------------------------------------------- # configuration options for the AutoGen Definitions output #--------------------------------------------------------------------------- GENERATE_AUTOGEN_DEF = NO #--------------------------------------------------------------------------- # configuration options related to the Perl module output #--------------------------------------------------------------------------- GENERATE_PERLMOD = NO PERLMOD_LATEX = NO PERLMOD_PRETTY = YES PERLMOD_MAKEVAR_PREFIX = #--------------------------------------------------------------------------- # Configuration options related to the preprocessor #--------------------------------------------------------------------------- ENABLE_PREPROCESSING = YES MACRO_EXPANSION = YES EXPAND_ONLY_PREDEF = YES SEARCH_INCLUDES = YES INCLUDE_PATH = INCLUDE_FILE_PATTERNS = PREDEFINED = DEBUG=0 EXPAND_AS_DEFINED = SKIP_FUNCTION_MACROS = YES #--------------------------------------------------------------------------- # Configuration::additions related to external references #--------------------------------------------------------------------------- TAGFILES = GENERATE_TAGFILE = ALLEXTERNALS = NO EXTERNAL_GROUPS = YES PERL_PATH = /usr/bin/perl #--------------------------------------------------------------------------- # Configuration options related to the dot tool #--------------------------------------------------------------------------- CLASS_DIAGRAMS = YES HIDE_UNDOC_RELATIONS = YES HAVE_DOT = NO CLASS_GRAPH = YES COLLABORATION_GRAPH = YES UML_LOOK = NO TEMPLATE_RELATIONS = NO INCLUDE_GRAPH = YES INCLUDED_BY_GRAPH = YES CALL_GRAPH = NO GRAPHICAL_HIERARCHY = YES DOT_IMAGE_FORMAT = png DOT_PATH = DOTFILE_DIRS = MAX_DOT_GRAPH_WIDTH = 1024 MAX_DOT_GRAPH_HEIGHT = 1024 MAX_DOT_GRAPH_DEPTH = 0 GENERATE_LEGEND = YES DOT_CLEANUP = YES #--------------------------------------------------------------------------- # Configuration::additions related to the search engine #--------------------------------------------------------------------------- SEARCHENGINE = NO nxcl-0.9/doc/.svn/text-base/Doxyfile.in.svn-base0000444000175000017500000001747410764221506020171 0ustar mjj29mjj29# Doxyfile 1.3.6 #--------------------------------------------------------------------------- # Project related configuration options #--------------------------------------------------------------------------- PROJECT_NAME = nxcl PROJECT_NUMBER = @VERSION@ OUTPUT_DIRECTORY = OUTPUT_LANGUAGE = English USE_WINDOWS_ENCODING = NO BRIEF_MEMBER_DESC = YES REPEAT_BRIEF = YES ABBREVIATE_BRIEF = ALWAYS_DETAILED_SEC = NO INLINE_INHERITED_MEMB = NO FULL_PATH_NAMES = NO STRIP_FROM_PATH = SHORT_NAMES = NO JAVADOC_AUTOBRIEF = NO MULTILINE_CPP_IS_BRIEF = NO DETAILS_AT_TOP = NO INHERIT_DOCS = YES DISTRIBUTE_GROUP_DOC = NO TAB_SIZE = 8 ALIASES = OPTIMIZE_OUTPUT_FOR_C = NO OPTIMIZE_OUTPUT_JAVA = NO SUBGROUPING = YES #--------------------------------------------------------------------------- # Build related configuration options #--------------------------------------------------------------------------- EXTRACT_ALL = NO EXTRACT_PRIVATE = NO EXTRACT_STATIC = NO EXTRACT_LOCAL_CLASSES = YES HIDE_UNDOC_MEMBERS = NO HIDE_UNDOC_CLASSES = NO HIDE_FRIEND_COMPOUNDS = NO HIDE_IN_BODY_DOCS = NO INTERNAL_DOCS = NO CASE_SENSE_NAMES = YES HIDE_SCOPE_NAMES = NO SHOW_INCLUDE_FILES = YES INLINE_INFO = YES SORT_MEMBER_DOCS = YES SORT_BRIEF_DOCS = NO SORT_BY_SCOPE_NAME = NO GENERATE_TODOLIST = YES GENERATE_TESTLIST = YES GENERATE_BUGLIST = YES GENERATE_DEPRECATEDLIST= YES ENABLED_SECTIONS = MAX_INITIALIZER_LINES = 30 SHOW_USED_FILES = YES #--------------------------------------------------------------------------- # configuration options related to warning and progress messages #--------------------------------------------------------------------------- QUIET = NO WARNINGS = YES WARN_IF_UNDOCUMENTED = YES WARN_IF_DOC_ERROR = YES WARN_FORMAT = "$file:$line: $text" WARN_LOGFILE = #--------------------------------------------------------------------------- # configuration options related to the input files #--------------------------------------------------------------------------- INPUT = .. ../nxcl ../lib ../test FILE_PATTERNS = *.h RECURSIVE = NO EXCLUDE = EXCLUDE_SYMLINKS = NO EXCLUDE_PATTERNS = EXAMPLE_PATH = EXAMPLE_PATTERNS = EXAMPLE_RECURSIVE = NO IMAGE_PATH = images INPUT_FILTER = FILTER_SOURCE_FILES = NO #--------------------------------------------------------------------------- # configuration options related to source browsing #--------------------------------------------------------------------------- SOURCE_BROWSER = YES INLINE_SOURCES = NO STRIP_CODE_COMMENTS = YES REFERENCED_BY_RELATION = YES REFERENCES_RELATION = YES VERBATIM_HEADERS = YES #--------------------------------------------------------------------------- # configuration options related to the alphabetical class index #--------------------------------------------------------------------------- ALPHABETICAL_INDEX = NO COLS_IN_ALPHA_INDEX = 4 IGNORE_PREFIX = #--------------------------------------------------------------------------- # configuration options related to the HTML output #--------------------------------------------------------------------------- GENERATE_HTML = YES HTML_OUTPUT = html HTML_FILE_EXTENSION = .html HTML_HEADER = HTML_FOOTER = HTML_STYLESHEET = HTML_ALIGN_MEMBERS = YES GENERATE_HTMLHELP = NO CHM_FILE = HHC_LOCATION = GENERATE_CHI = NO BINARY_TOC = NO TOC_EXPAND = NO DISABLE_INDEX = NO ENUM_VALUES_PER_LINE = 4 GENERATE_TREEVIEW = NO TREEVIEW_WIDTH = 250 #--------------------------------------------------------------------------- # configuration options related to the LaTeX output #--------------------------------------------------------------------------- GENERATE_LATEX = NO LATEX_OUTPUT = latex LATEX_CMD_NAME = latex MAKEINDEX_CMD_NAME = makeindex COMPACT_LATEX = NO PAPER_TYPE = a4wide EXTRA_PACKAGES = LATEX_HEADER = PDF_HYPERLINKS = NO USE_PDFLATEX = NO LATEX_BATCHMODE = NO LATEX_HIDE_INDICES = NO #--------------------------------------------------------------------------- # configuration options related to the RTF output #--------------------------------------------------------------------------- GENERATE_RTF = NO RTF_OUTPUT = rtf COMPACT_RTF = NO RTF_HYPERLINKS = NO RTF_STYLESHEET_FILE = RTF_EXTENSIONS_FILE = #--------------------------------------------------------------------------- # configuration options related to the man page output #--------------------------------------------------------------------------- GENERATE_MAN = NO MAN_OUTPUT = man MAN_EXTENSION = .3 MAN_LINKS = NO #--------------------------------------------------------------------------- # configuration options related to the XML output #--------------------------------------------------------------------------- GENERATE_XML = NO XML_OUTPUT = xml XML_SCHEMA = XML_DTD = XML_PROGRAMLISTING = YES #--------------------------------------------------------------------------- # configuration options for the AutoGen Definitions output #--------------------------------------------------------------------------- GENERATE_AUTOGEN_DEF = NO #--------------------------------------------------------------------------- # configuration options related to the Perl module output #--------------------------------------------------------------------------- GENERATE_PERLMOD = NO PERLMOD_LATEX = NO PERLMOD_PRETTY = YES PERLMOD_MAKEVAR_PREFIX = #--------------------------------------------------------------------------- # Configuration options related to the preprocessor #--------------------------------------------------------------------------- ENABLE_PREPROCESSING = YES MACRO_EXPANSION = YES EXPAND_ONLY_PREDEF = YES SEARCH_INCLUDES = YES INCLUDE_PATH = INCLUDE_FILE_PATTERNS = PREDEFINED = DEBUG=0 EXPAND_AS_DEFINED = SKIP_FUNCTION_MACROS = YES #--------------------------------------------------------------------------- # Configuration::additions related to external references #--------------------------------------------------------------------------- TAGFILES = GENERATE_TAGFILE = ALLEXTERNALS = NO EXTERNAL_GROUPS = YES PERL_PATH = /usr/bin/perl #--------------------------------------------------------------------------- # Configuration options related to the dot tool #--------------------------------------------------------------------------- CLASS_DIAGRAMS = YES HIDE_UNDOC_RELATIONS = YES HAVE_DOT = NO CLASS_GRAPH = YES COLLABORATION_GRAPH = YES UML_LOOK = NO TEMPLATE_RELATIONS = NO INCLUDE_GRAPH = YES INCLUDED_BY_GRAPH = YES CALL_GRAPH = NO GRAPHICAL_HIERARCHY = YES DOT_IMAGE_FORMAT = png DOT_PATH = DOTFILE_DIRS = MAX_DOT_GRAPH_WIDTH = 1024 MAX_DOT_GRAPH_HEIGHT = 1024 MAX_DOT_GRAPH_DEPTH = 0 GENERATE_LEGEND = YES DOT_CLEANUP = YES #--------------------------------------------------------------------------- # Configuration::additions related to the search engine #--------------------------------------------------------------------------- SEARCHENGINE = NO nxcl-0.9/doc/.svn/text-base/Makefile.am.svn-base0000444000175000017500000000120510764221506020073 0ustar mjj29mjj29CLEANFILES = *~ DOXYFILE = Doxyfile docdir = $(prefix)/doc/$(PACKAGE)-$(VERSION) EXTRA_DIST = html SEDCMD1 = s/$$title/GNU nxcl documentation version $(VERSION)/g SEDCMD2 = s/$$(VERSION)/$(VERSION)/g all: html html: doxygen install-data-local: $(mkinstalldirs) $(DESTDIR)$(docdir) @for file in $(srcdir)/html/*; do \ bn="`basename $$file`"; \ echo " $(INSTALL_DATA) $$file $(DESTDIR)$(docdir)/$$bn"; \ $(INSTALL_DATA) $$file $(DESTDIR)$(docdir)/$$bn; \ done uninstall-local: @for file in $(srcdir)/html/*; do \ bn="`basename $$file`"; \ echo " rm -f $(DESTDIR)$(docdir)/$$bn"; \ rm -f $(DESTDIR)$(docdir)/$$bn; \ done nxcl-0.9/doc/.svn/prop-base/0000755000175000017500000000000010764221506014322 5ustar mjj29mjj29nxcl-0.9/doc/.svn/props/0000755000175000017500000000000010764221506013575 5ustar mjj29mjj29nxcl-0.9/doc/.svn/tmp/0000755000175000017500000000000010764221506013232 5ustar mjj29mjj29nxcl-0.9/doc/.svn/tmp/text-base/0000755000175000017500000000000010764221506015126 5ustar mjj29mjj29nxcl-0.9/doc/.svn/tmp/prop-base/0000755000175000017500000000000010764221506015122 5ustar mjj29mjj29nxcl-0.9/doc/.svn/tmp/props/0000755000175000017500000000000010764221506014375 5ustar mjj29mjj29nxcl-0.9/doc/.svn/entries0000444000175000017500000000112210764221506014020 0ustar mjj29mjj298 dir 500 svn://svn.berlios.de/freenx/tags/nxcl-0.9/doc svn://svn.berlios.de/freenx 2007-09-11T12:48:46.240816Z 373 sebjames svn:special svn:externals svn:needs-lock 80778403-ebee-0310-8e0a-e86a689f3fff Doxyfile file 2008-03-07T11:13:10.000000Z 52f9d51c5c20d6bc7cb7e82c7e39c2d5 2007-09-11T12:48:46.240816Z 373 sebjames Doxyfile.in file 2008-03-07T11:13:10.000000Z 52f9d51c5c20d6bc7cb7e82c7e39c2d5 2007-09-11T12:48:46.240816Z 373 sebjames Makefile.am file 2008-03-07T11:13:10.000000Z 6f245f2ffd4bfb92ca7c0e1630226473 2007-09-11T12:48:46.240816Z 373 sebjames nxcl-0.9/doc/.svn/format0000444000175000017500000000000210764221506013633 0ustar mjj29mjj298 nxcl-0.9/doc/Doxyfile0000644000175000017500000001747410764221506013271 0ustar mjj29mjj29# Doxyfile 1.3.6 #--------------------------------------------------------------------------- # Project related configuration options #--------------------------------------------------------------------------- PROJECT_NAME = nxcl PROJECT_NUMBER = @VERSION@ OUTPUT_DIRECTORY = OUTPUT_LANGUAGE = English USE_WINDOWS_ENCODING = NO BRIEF_MEMBER_DESC = YES REPEAT_BRIEF = YES ABBREVIATE_BRIEF = ALWAYS_DETAILED_SEC = NO INLINE_INHERITED_MEMB = NO FULL_PATH_NAMES = NO STRIP_FROM_PATH = SHORT_NAMES = NO JAVADOC_AUTOBRIEF = NO MULTILINE_CPP_IS_BRIEF = NO DETAILS_AT_TOP = NO INHERIT_DOCS = YES DISTRIBUTE_GROUP_DOC = NO TAB_SIZE = 8 ALIASES = OPTIMIZE_OUTPUT_FOR_C = NO OPTIMIZE_OUTPUT_JAVA = NO SUBGROUPING = YES #--------------------------------------------------------------------------- # Build related configuration options #--------------------------------------------------------------------------- EXTRACT_ALL = NO EXTRACT_PRIVATE = NO EXTRACT_STATIC = NO EXTRACT_LOCAL_CLASSES = YES HIDE_UNDOC_MEMBERS = NO HIDE_UNDOC_CLASSES = NO HIDE_FRIEND_COMPOUNDS = NO HIDE_IN_BODY_DOCS = NO INTERNAL_DOCS = NO CASE_SENSE_NAMES = YES HIDE_SCOPE_NAMES = NO SHOW_INCLUDE_FILES = YES INLINE_INFO = YES SORT_MEMBER_DOCS = YES SORT_BRIEF_DOCS = NO SORT_BY_SCOPE_NAME = NO GENERATE_TODOLIST = YES GENERATE_TESTLIST = YES GENERATE_BUGLIST = YES GENERATE_DEPRECATEDLIST= YES ENABLED_SECTIONS = MAX_INITIALIZER_LINES = 30 SHOW_USED_FILES = YES #--------------------------------------------------------------------------- # configuration options related to warning and progress messages #--------------------------------------------------------------------------- QUIET = NO WARNINGS = YES WARN_IF_UNDOCUMENTED = YES WARN_IF_DOC_ERROR = YES WARN_FORMAT = "$file:$line: $text" WARN_LOGFILE = #--------------------------------------------------------------------------- # configuration options related to the input files #--------------------------------------------------------------------------- INPUT = .. ../nxcl ../lib ../test FILE_PATTERNS = *.h RECURSIVE = NO EXCLUDE = EXCLUDE_SYMLINKS = NO EXCLUDE_PATTERNS = EXAMPLE_PATH = EXAMPLE_PATTERNS = EXAMPLE_RECURSIVE = NO IMAGE_PATH = images INPUT_FILTER = FILTER_SOURCE_FILES = NO #--------------------------------------------------------------------------- # configuration options related to source browsing #--------------------------------------------------------------------------- SOURCE_BROWSER = YES INLINE_SOURCES = NO STRIP_CODE_COMMENTS = YES REFERENCED_BY_RELATION = YES REFERENCES_RELATION = YES VERBATIM_HEADERS = YES #--------------------------------------------------------------------------- # configuration options related to the alphabetical class index #--------------------------------------------------------------------------- ALPHABETICAL_INDEX = NO COLS_IN_ALPHA_INDEX = 4 IGNORE_PREFIX = #--------------------------------------------------------------------------- # configuration options related to the HTML output #--------------------------------------------------------------------------- GENERATE_HTML = YES HTML_OUTPUT = html HTML_FILE_EXTENSION = .html HTML_HEADER = HTML_FOOTER = HTML_STYLESHEET = HTML_ALIGN_MEMBERS = YES GENERATE_HTMLHELP = NO CHM_FILE = HHC_LOCATION = GENERATE_CHI = NO BINARY_TOC = NO TOC_EXPAND = NO DISABLE_INDEX = NO ENUM_VALUES_PER_LINE = 4 GENERATE_TREEVIEW = NO TREEVIEW_WIDTH = 250 #--------------------------------------------------------------------------- # configuration options related to the LaTeX output #--------------------------------------------------------------------------- GENERATE_LATEX = NO LATEX_OUTPUT = latex LATEX_CMD_NAME = latex MAKEINDEX_CMD_NAME = makeindex COMPACT_LATEX = NO PAPER_TYPE = a4wide EXTRA_PACKAGES = LATEX_HEADER = PDF_HYPERLINKS = NO USE_PDFLATEX = NO LATEX_BATCHMODE = NO LATEX_HIDE_INDICES = NO #--------------------------------------------------------------------------- # configuration options related to the RTF output #--------------------------------------------------------------------------- GENERATE_RTF = NO RTF_OUTPUT = rtf COMPACT_RTF = NO RTF_HYPERLINKS = NO RTF_STYLESHEET_FILE = RTF_EXTENSIONS_FILE = #--------------------------------------------------------------------------- # configuration options related to the man page output #--------------------------------------------------------------------------- GENERATE_MAN = NO MAN_OUTPUT = man MAN_EXTENSION = .3 MAN_LINKS = NO #--------------------------------------------------------------------------- # configuration options related to the XML output #--------------------------------------------------------------------------- GENERATE_XML = NO XML_OUTPUT = xml XML_SCHEMA = XML_DTD = XML_PROGRAMLISTING = YES #--------------------------------------------------------------------------- # configuration options for the AutoGen Definitions output #--------------------------------------------------------------------------- GENERATE_AUTOGEN_DEF = NO #--------------------------------------------------------------------------- # configuration options related to the Perl module output #--------------------------------------------------------------------------- GENERATE_PERLMOD = NO PERLMOD_LATEX = NO PERLMOD_PRETTY = YES PERLMOD_MAKEVAR_PREFIX = #--------------------------------------------------------------------------- # Configuration options related to the preprocessor #--------------------------------------------------------------------------- ENABLE_PREPROCESSING = YES MACRO_EXPANSION = YES EXPAND_ONLY_PREDEF = YES SEARCH_INCLUDES = YES INCLUDE_PATH = INCLUDE_FILE_PATTERNS = PREDEFINED = DEBUG=0 EXPAND_AS_DEFINED = SKIP_FUNCTION_MACROS = YES #--------------------------------------------------------------------------- # Configuration::additions related to external references #--------------------------------------------------------------------------- TAGFILES = GENERATE_TAGFILE = ALLEXTERNALS = NO EXTERNAL_GROUPS = YES PERL_PATH = /usr/bin/perl #--------------------------------------------------------------------------- # Configuration options related to the dot tool #--------------------------------------------------------------------------- CLASS_DIAGRAMS = YES HIDE_UNDOC_RELATIONS = YES HAVE_DOT = NO CLASS_GRAPH = YES COLLABORATION_GRAPH = YES UML_LOOK = NO TEMPLATE_RELATIONS = NO INCLUDE_GRAPH = YES INCLUDED_BY_GRAPH = YES CALL_GRAPH = NO GRAPHICAL_HIERARCHY = YES DOT_IMAGE_FORMAT = png DOT_PATH = DOTFILE_DIRS = MAX_DOT_GRAPH_WIDTH = 1024 MAX_DOT_GRAPH_HEIGHT = 1024 MAX_DOT_GRAPH_DEPTH = 0 GENERATE_LEGEND = YES DOT_CLEANUP = YES #--------------------------------------------------------------------------- # Configuration::additions related to the search engine #--------------------------------------------------------------------------- SEARCHENGINE = NO nxcl-0.9/doc/Doxyfile.in0000644000175000017500000001747410764221506013676 0ustar mjj29mjj29# Doxyfile 1.3.6 #--------------------------------------------------------------------------- # Project related configuration options #--------------------------------------------------------------------------- PROJECT_NAME = nxcl PROJECT_NUMBER = @VERSION@ OUTPUT_DIRECTORY = OUTPUT_LANGUAGE = English USE_WINDOWS_ENCODING = NO BRIEF_MEMBER_DESC = YES REPEAT_BRIEF = YES ABBREVIATE_BRIEF = ALWAYS_DETAILED_SEC = NO INLINE_INHERITED_MEMB = NO FULL_PATH_NAMES = NO STRIP_FROM_PATH = SHORT_NAMES = NO JAVADOC_AUTOBRIEF = NO MULTILINE_CPP_IS_BRIEF = NO DETAILS_AT_TOP = NO INHERIT_DOCS = YES DISTRIBUTE_GROUP_DOC = NO TAB_SIZE = 8 ALIASES = OPTIMIZE_OUTPUT_FOR_C = NO OPTIMIZE_OUTPUT_JAVA = NO SUBGROUPING = YES #--------------------------------------------------------------------------- # Build related configuration options #--------------------------------------------------------------------------- EXTRACT_ALL = NO EXTRACT_PRIVATE = NO EXTRACT_STATIC = NO EXTRACT_LOCAL_CLASSES = YES HIDE_UNDOC_MEMBERS = NO HIDE_UNDOC_CLASSES = NO HIDE_FRIEND_COMPOUNDS = NO HIDE_IN_BODY_DOCS = NO INTERNAL_DOCS = NO CASE_SENSE_NAMES = YES HIDE_SCOPE_NAMES = NO SHOW_INCLUDE_FILES = YES INLINE_INFO = YES SORT_MEMBER_DOCS = YES SORT_BRIEF_DOCS = NO SORT_BY_SCOPE_NAME = NO GENERATE_TODOLIST = YES GENERATE_TESTLIST = YES GENERATE_BUGLIST = YES GENERATE_DEPRECATEDLIST= YES ENABLED_SECTIONS = MAX_INITIALIZER_LINES = 30 SHOW_USED_FILES = YES #--------------------------------------------------------------------------- # configuration options related to warning and progress messages #--------------------------------------------------------------------------- QUIET = NO WARNINGS = YES WARN_IF_UNDOCUMENTED = YES WARN_IF_DOC_ERROR = YES WARN_FORMAT = "$file:$line: $text" WARN_LOGFILE = #--------------------------------------------------------------------------- # configuration options related to the input files #--------------------------------------------------------------------------- INPUT = .. ../nxcl ../lib ../test FILE_PATTERNS = *.h RECURSIVE = NO EXCLUDE = EXCLUDE_SYMLINKS = NO EXCLUDE_PATTERNS = EXAMPLE_PATH = EXAMPLE_PATTERNS = EXAMPLE_RECURSIVE = NO IMAGE_PATH = images INPUT_FILTER = FILTER_SOURCE_FILES = NO #--------------------------------------------------------------------------- # configuration options related to source browsing #--------------------------------------------------------------------------- SOURCE_BROWSER = YES INLINE_SOURCES = NO STRIP_CODE_COMMENTS = YES REFERENCED_BY_RELATION = YES REFERENCES_RELATION = YES VERBATIM_HEADERS = YES #--------------------------------------------------------------------------- # configuration options related to the alphabetical class index #--------------------------------------------------------------------------- ALPHABETICAL_INDEX = NO COLS_IN_ALPHA_INDEX = 4 IGNORE_PREFIX = #--------------------------------------------------------------------------- # configuration options related to the HTML output #--------------------------------------------------------------------------- GENERATE_HTML = YES HTML_OUTPUT = html HTML_FILE_EXTENSION = .html HTML_HEADER = HTML_FOOTER = HTML_STYLESHEET = HTML_ALIGN_MEMBERS = YES GENERATE_HTMLHELP = NO CHM_FILE = HHC_LOCATION = GENERATE_CHI = NO BINARY_TOC = NO TOC_EXPAND = NO DISABLE_INDEX = NO ENUM_VALUES_PER_LINE = 4 GENERATE_TREEVIEW = NO TREEVIEW_WIDTH = 250 #--------------------------------------------------------------------------- # configuration options related to the LaTeX output #--------------------------------------------------------------------------- GENERATE_LATEX = NO LATEX_OUTPUT = latex LATEX_CMD_NAME = latex MAKEINDEX_CMD_NAME = makeindex COMPACT_LATEX = NO PAPER_TYPE = a4wide EXTRA_PACKAGES = LATEX_HEADER = PDF_HYPERLINKS = NO USE_PDFLATEX = NO LATEX_BATCHMODE = NO LATEX_HIDE_INDICES = NO #--------------------------------------------------------------------------- # configuration options related to the RTF output #--------------------------------------------------------------------------- GENERATE_RTF = NO RTF_OUTPUT = rtf COMPACT_RTF = NO RTF_HYPERLINKS = NO RTF_STYLESHEET_FILE = RTF_EXTENSIONS_FILE = #--------------------------------------------------------------------------- # configuration options related to the man page output #--------------------------------------------------------------------------- GENERATE_MAN = NO MAN_OUTPUT = man MAN_EXTENSION = .3 MAN_LINKS = NO #--------------------------------------------------------------------------- # configuration options related to the XML output #--------------------------------------------------------------------------- GENERATE_XML = NO XML_OUTPUT = xml XML_SCHEMA = XML_DTD = XML_PROGRAMLISTING = YES #--------------------------------------------------------------------------- # configuration options for the AutoGen Definitions output #--------------------------------------------------------------------------- GENERATE_AUTOGEN_DEF = NO #--------------------------------------------------------------------------- # configuration options related to the Perl module output #--------------------------------------------------------------------------- GENERATE_PERLMOD = NO PERLMOD_LATEX = NO PERLMOD_PRETTY = YES PERLMOD_MAKEVAR_PREFIX = #--------------------------------------------------------------------------- # Configuration options related to the preprocessor #--------------------------------------------------------------------------- ENABLE_PREPROCESSING = YES MACRO_EXPANSION = YES EXPAND_ONLY_PREDEF = YES SEARCH_INCLUDES = YES INCLUDE_PATH = INCLUDE_FILE_PATTERNS = PREDEFINED = DEBUG=0 EXPAND_AS_DEFINED = SKIP_FUNCTION_MACROS = YES #--------------------------------------------------------------------------- # Configuration::additions related to external references #--------------------------------------------------------------------------- TAGFILES = GENERATE_TAGFILE = ALLEXTERNALS = NO EXTERNAL_GROUPS = YES PERL_PATH = /usr/bin/perl #--------------------------------------------------------------------------- # Configuration options related to the dot tool #--------------------------------------------------------------------------- CLASS_DIAGRAMS = YES HIDE_UNDOC_RELATIONS = YES HAVE_DOT = NO CLASS_GRAPH = YES COLLABORATION_GRAPH = YES UML_LOOK = NO TEMPLATE_RELATIONS = NO INCLUDE_GRAPH = YES INCLUDED_BY_GRAPH = YES CALL_GRAPH = NO GRAPHICAL_HIERARCHY = YES DOT_IMAGE_FORMAT = png DOT_PATH = DOTFILE_DIRS = MAX_DOT_GRAPH_WIDTH = 1024 MAX_DOT_GRAPH_HEIGHT = 1024 MAX_DOT_GRAPH_DEPTH = 0 GENERATE_LEGEND = YES DOT_CLEANUP = YES #--------------------------------------------------------------------------- # Configuration::additions related to the search engine #--------------------------------------------------------------------------- SEARCHENGINE = NO nxcl-0.9/doc/Makefile.am0000644000175000017500000000120510764221506013600 0ustar mjj29mjj29CLEANFILES = *~ DOXYFILE = Doxyfile docdir = $(prefix)/doc/$(PACKAGE)-$(VERSION) EXTRA_DIST = html SEDCMD1 = s/$$title/GNU nxcl documentation version $(VERSION)/g SEDCMD2 = s/$$(VERSION)/$(VERSION)/g all: html html: doxygen install-data-local: $(mkinstalldirs) $(DESTDIR)$(docdir) @for file in $(srcdir)/html/*; do \ bn="`basename $$file`"; \ echo " $(INSTALL_DATA) $$file $(DESTDIR)$(docdir)/$$bn"; \ $(INSTALL_DATA) $$file $(DESTDIR)$(docdir)/$$bn; \ done uninstall-local: @for file in $(srcdir)/html/*; do \ bn="`basename $$file`"; \ echo " rm -f $(DESTDIR)$(docdir)/$$bn"; \ rm -f $(DESTDIR)$(docdir)/$$bn; \ done nxcl-0.9/lib/0000755000175000017500000000000010764221506011547 5ustar mjj29mjj29nxcl-0.9/lib/.svn/0000755000175000017500000000000010764221506012433 5ustar mjj29mjj29nxcl-0.9/lib/.svn/text-base/0000755000175000017500000000000010764221506014327 5ustar mjj29mjj29nxcl-0.9/lib/.svn/text-base/nxsession.h.svn-base0000444000175000017500000001357310764221506020255 0ustar mjj29mjj29/*************************************************************************** nxsession.h ------------------- begin : Sat 22nd July 2006 modifications : July 2007 copyright : (C) 2006 by George Wright modifications : (C) 2007 Embedded Software Foundry Ltd. (U.K.) : Author: Sebastian James : (C) 2008 Defuturo Ltd : Author: George Wright email : seb@esfnet.co.uk, gwright@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #ifndef _NXSESSION_H_ #define _NXSESSION_H_ #include #include #include #include #include "nxdata.h" #include namespace nxcl { /*! * Virtual Callback class. These callbacks are called based on * the output which we get from the nxssh process. */ class NXSessionCallbacks { public: NXSessionCallbacks() {} virtual ~NXSessionCallbacks() {} virtual void noSessionsSignal (void) {} virtual void loginFailedSignal (void) {} virtual void readyForProxySignal (void) {} /*! * Emitted when the initial public key authentication * is successful */ virtual void authenticatedSignal (void) {} virtual void sessionsSignal (list) {} }; /*! * This class is used to parse the output from the nxssh * session to the server. */ class NXSession { public: NXSession(); ~NXSession(); string parseSSH (string); int parseResponse (string); void parseResumeSessions (list); void resetSession (void); void wipeSessions (void); bool chooseResumable (int n); bool terminateSession (int n); string generateCookie (void); void runSession (void) { sessionDataSet = true; } /*! * Accessors */ //@{ void setUsername (string& user) { nxUsername = user; } void setPassword (string& pass) { nxPassword = pass; } void setResolution (int x, int y) { this->sessionData->xRes = x; this->sessionData->yRes = y; } void setDepth (int d) { this->sessionData->depth = d; } void setRender (bool isRender) { if (this->sessionDataSet) { this->sessionData->render = isRender; } } void setEncryption (bool enc) { if (this->sessionDataSet) { this->sessionData->encryption = enc; } } void setContinue (bool allow) { doSSH = allow; } void setSessionData (NXSessionData*); NXSessionData* getSessionData() { return this->sessionData; } bool getSessionDataSet (void) { return this->sessionDataSet; } void setCallbacks (NXSessionCallbacks * cb) { this->callbacks = cb; } //@} private: void reset (void); void fillRand(unsigned char *, size_t); /*! * This is the answer to give to the ssh server if it * asks whether we want to continue (say, if we're * connecting for the first time and we don't * necessarily trust its SSL key). */ bool doSSH; /*! * Set to true if there are suspended sessions on the * server which are owned by nxUsername. */ bool suspendedSessions; /*! * Set to true of sessionData has been populated */ bool sessionDataSet; /*! * Holds the stage of the process which we have * reached as we go through the process of * authenticating with the NX Server. */ int stage; /*! * File descriptor for the random number device */ int devurand_fd; /*! * Holds the username for this session */ string nxUsername; /*! * Holds the password for this session */ string nxPassword; /*! * A list of sessions which can be resumed, as strings. */ list resumeSessions; /*! * A list of running sessions, held as NXResumeData * structures. */ list runningSessions; /*! * Data for this session. */ NXSessionData *sessionData; /*! * Pointer to a class containing callback methods. */ NXSessionCallbacks * callbacks; }; } // namespace #endif nxcl-0.9/lib/.svn/text-base/nxclientlib_i18n.h.svn-base0000444000175000017500000000140510764221506021365 0ustar mjj29mjj29extern "C" { #ifndef __NXCLIENTLIB_I18N__ # define __NXCLIENTLIB_I18N__ #define _(String) (String) #define N_(String) String /* # ifdef HAVE_CONFIG_H # include # endif # ifdef ENABLE_NLS # include "../lib/gettext.h" # define _(String) gettext (String) # define gettext_noop(String) String # define N_(String) gettext_noop (String) # else # define _(String) (String) # define N_(String) String # define textdomain(Domain) (Domain) # define gettext(String) (String) # define dgettext(Domain,String) (String) # define dcgettext(Domain,String,Type) (String) # define bindtextdomain(Domain, Directory) (Domain) # define bind_textdomain_codeset(Domain,Codeset) (Codeset) # endif */ #endif /* __NXCLIENTLIB_I18N__ */ } nxcl-0.9/lib/.svn/text-base/nxclientlib.h.svn-base0000444000175000017500000003454710764221506020543 0ustar mjj29mjj29/*************************************************************************** nxclientlib.h ------------------- begin : Sat 22nd July 2006 remove Qt dependency : Started June 2007 modifications : June-July 2007 copyright : (C) 2006 by George Wright modifications : (C) 2007 Embedded Software Foundry Ltd. (U.K.) : Author: Sebastian James : (C) 2008 Defuturo Ltd : Author: George Wright email : seb@esfnet.co.uk, gwright@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #ifndef _NXCLIENTLIB_H_ #define _NXCLIENTLIB_H_ #include #include "nxsession.h" #include #include "notQt.h" using namespace std; namespace nxcl { struct ProxyData { string id; int display; string cookie; string proxyIP; bool encrypted; int port; string server; }; /*! * Callbacks which are to be defined by the client code of * NXClientLib objects. In the case of nxcl, that means the * code in the class Nxcl in nxcl.cpp. */ class NXClientLibExternalCallbacks { public: NXClientLibExternalCallbacks () {} virtual ~NXClientLibExternalCallbacks () {} virtual void write (string msg) {} virtual void write (int num, string msg) {} virtual void error (string msg) {} virtual void debug (string msg) {} virtual void stdoutSignal (string msg) {} virtual void stderrSignal (string msg) {} virtual void stdinSignal (string msg) {} virtual void resumeSessionsSignal (list) {} virtual void noSessionsSignal (void) {} virtual void serverCapacitySignal (void) {} virtual void connectedSuccessfullySignal (void) {} }; /*! * Have to derive NXClientLib from an abstract base class, * NXClientLibBase, so that NXClientLibCallbacks can * hold a pointer to an NXClientLib object. * * The functions that are declared in NXClientLibBase are the * ones that we want to call via this->parent in * NXClientLibCallbacks. They're the ones that are called from * within objects of other classes (such as this->session * (NXSession) or this->nxsshProcess (notQProcess). */ class NXClientLibBase { public: NXClientLibBase() {} virtual ~NXClientLibBase() {} virtual void setIsFinished (bool status) {} virtual void processParseStdout (void) {} virtual void processParseStderr (void) {} virtual void loginFailed (void) {} virtual void readyproxy (void) {} virtual void doneAuth (void) {} /*! * External callbacks pointer is held in NXClientLibBase * because NXClientLibProcessCallbacks::parent is of * type NXClientLibBase and in NXClientLibProcessCallbacks we * refer to this->parent->externalCallbacks->write() */ NXClientLibExternalCallbacks * externalCallbacks; }; /*! * Callbacks class. This derives from several other base * callbacks classes, defining the behaviour of the callbacks. */ class NXClientLibCallbacks : public notQProcessCallbacks, public NXSessionCallbacks { public: NXClientLibCallbacks(); ~NXClientLibCallbacks(); /*! * The callback signals */ //@{ /*! * From notQProcess: */ //@{ void startedSignal (string name); void errorSignal (int error); void processFinishedSignal (string name); void readyReadStandardOutputSignal (void); void readyReadStandardErrorSignal (void); //@} /*! * From NXSession: */ //@{ void noSessionsSignal (void); void loginFailedSignal (void); void readyForProxySignal (void); void authenticatedSignal (void); void sessionsSignal (list); //@} //@} /*! * Accessor function to set a pointer to the parent NXCLientLib * object. */ void setParent (NXClientLibBase * p) { this->parent = p; } private: NXClientLibBase * parent; }; class NXClientLib : public NXClientLibBase { public: NXClientLib(); ~NXClientLib(); /*! * Set up data and then call this->nxsshProcess.start(). * * \param publicKey is the path to the ssh public key * file to authenticate with. Pass "supplied" to use * a new key, which you should then supply as the * parameter key. * * \param serverHost is the hostname of the NX server to * connect to * * \param encryption is whether to use an encrypted NX * session * * \param key ssh key to use for authentication of the * nx user if publicKey is "supplied". * * \param port TCP port to use for the ssh connection. */ void invokeNXSSH (string publicKey = "supplied", string serverHost = "", bool encryption = true, string key = "", int port = 22); /*! * Overloaded to give callback data on write. * * Writes data to this->nxsshProcess stdin and also * out to the user via stdoutCallback */ void write (string data); /*! * Sets a custom binary search path */ void setCustomPath(string path) { this->customPath = path; } /*! * Passes auth to this->session.setContinue() */ void allowSSHConnect (bool auth); /*! * Set up data and then call this->nxproxyProcess.start() */ void invokeProxy (void); /*! * Parse a line of output from * this->nxsshProcess. This is called when the proxy * has started, or if NX authentication * failed. Otherwise, this->session.parseSSH() is * used. */ string parseSSH (string message); /*! * Read through the nx session file, and if we find a * message saying "Session: Terminating session at * 'some date'" we need to set isFinished to true. */ //void checkSession (void); /*! * Re-set the contents of this->session.sessionData * with the nth choice. * * \return true if the nth session is resumable, false * if not, or if there is no nth session. */ bool chooseResumable (int n); /*! * Re-set the contents of this->session.sessionData * with the nth choice such that a terminate session * message will be sent to the nxserver * * \return true if the nth session is terminatable, false * if not, or if there is no nth session. */ bool terminateSession (int n); void runSession (void); void startX11 (string resolution, string name); bool needX11Probe (void) { return x11Probe; } // public slots: //@{ void doneAuth (void); void loginFailed (void); void finished (void) { dbgln ("Finishing up on signal"); this->isFinished = true; } void readyproxy (void) { dbgln ("ready for nxproxy"); this->readyForProxy = true; } void reset (void); void processParseStdout (void); void processParseStderr (void); /*! * SSH requests confirmation to go ahead with * connecting (e.g. if you haven't connected to the * host before) */ void requestConfirmation (string msg); //@} // Accessors //@{ /*! * Set the username for NX to log in with */ void setUsername (string& user) { this->nxuser = user; this->session.setUsername (this->nxuser); } /*! * Set the password for NX to log in with */ void setPassword (string& pass) { this->nxpass = pass; this->session.setPassword (this->nxpass); } void setResolution (int x, int y) { this->session.setResolution(x, y); } void setDepth (int depth) { this->session.setDepth(depth); } void setRender (bool render) { this->session.setRender(render); } void setSessionData (NXSessionData *); notQProcess* getNXSSHProcess (void) { return this->nxsshProcess; } notQProcess* getNXProxyProcess (void) { return this->nxproxyProcess; } notQProcess* getX11Process (void) { return this->x11Process; } notQProcess* getNXAuthProcess (void) { return this->nxauthProcess; } bool getIsFinished (void) { return this->isFinished; } bool getReadyForProxy (void) { return this->readyForProxy; } NXSession* getSession (void) { return &this->session; } void setIsFinished (bool status) { this->isFinished = status; } void setExternalCallbacks (NXClientLibExternalCallbacks * cb) { this->externalCallbacks = cb; } bool getSessionRunning (void) { return this->sessionRunning; } //@} private: /*! * Try a number of different paths to try to find the * program prog's full path. * * \param prog The program to find, likely to be nxssh * or nxproxy. * * \return The full path; e.g. /usr/bin/nxssh */ string getPath (string prog); /*! * Custom search path */ string customPath; bool x11Probe; /*! * Set true when the program is ready to end, e.g if * authentication failed, nxssh failed to start amoung * other reasons. */ bool isFinished; /*! * Set true when nxssh is ready to launch the nxproxy process. */ bool readyForProxy; /*! * Set true when the NX session is under way. This * means we can reduce the polling frequency right * down to a level which won't impact on power * consumption. */ bool sessionRunning; /*! * Have we said we need to enter a password? */ bool password; // FIXME: I hold the actual data, and a pointer to the // data here. I tried to get rid of the pointer, and // modify main.cpp in ../nxcl and that didn't work // properly - I'm not sure why. I suppose I could get // rid of the objects here, and then call // pNxsshProcess = new notQProcess; in the // constructor... /*! * The nxssh process object */ notQProcess* nxsshProcess; /*! * The nxproxy process object */ notQProcess* nxproxyProcess; /*! * The X11 process object */ notQProcess* x11Process; /*! * The nxauth process object */ notQProcess* nxauthProcess; /*! * A callbacks object. This holds the various callback * methods. The callback methods are defined here, but * are callable from notQProcess etc. */ NXClientLibCallbacks callbacks; /*! * A temporary file to hold the ssl key */ notQTemporaryFile *keyFile; /*! * The NX Session object. */ NXSession session; /*! * A structure holding information about the * connection to be made, such as server address, port * and id. */ ProxyData proxyData; /*! * Username for the connection */ string nxuser; /*! * Password for the connection */ string nxpass; }; } // namespace #endif nxcl-0.9/lib/.svn/text-base/i18n.h.svn-base0000444000175000017500000000126510764221506016776 0ustar mjj29mjj29#ifndef __NXCL_I18N__ # define __NXCL_I18N__ # ifdef HAVE_CONFIG_H # include # endif # ifdef ENABLE_NLS # include "../lib/gettext.h" # define _(String) gettext (String) # define gettext_noop(String) String # define N_(String) gettext_noop (String) # else # define _(String) (String) # define N_(String) String # define textdomain(Domain) (Domain) # define gettext(String) (String) # define dgettext(Domain,String) (String) # define dcgettext(Domain,String,Type) (String) # define bindtextdomain(Domain, Directory) (Domain) # define bind_textdomain_codeset(Domain,Codeset) (Codeset) # endif /* ENABLE_NLS */ #endif /* __NXCL_I18N__ */ nxcl-0.9/lib/.svn/text-base/nxdata.h.svn-base0000444000175000017500000000622510764221506017477 0ustar mjj29mjj29/*************************************************************************** nxdata.h ------------------- begin : Wednesday 9th August 2006 modifications : July 2007 copyright : (C) 2006 by George Wright modifications : (C) 2007 Embedded Software Foundry Ltd. (U.K.) : Author: Sebastian James email : seb@esfnet.co.uk, gwright@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #ifndef _NXDATA_H_ #define _NXDATA_H_ #include /*! * Some definitions of numbers that we can send over to the frontend * client to tell it how we're getting along with the connection... */ #define NXCL_PROCESS_STARTED 1000001 #define NXCL_PROCESS_EXITED 1000002 #define NXCL_AUTH_FAILED 1000003 #define NXCL_AUTHENTICATING 1000004 #define NXCL_LOGIN_FAILED 1000005 #define NXCL_HOST_KEY_VERIFAILED 1000006 #define NXCL_INVOKE_PROXY 1000007 #define NXCL_STARTING 1000008 #define NXCL_FINISHED 1000009 #define NXCL_ALIVE 1000010 #define NXCL_PROCESS_ERROR 1000011 using namespace std; namespace nxcl { struct NXConfigData { string serverHost; int serverPort; string sessionUser; string sessionPass; string sessionName; string sessionType; int cache; int images; string linkType; bool render; string backingstore; int imageCompressionMethod; int imageCompressionLevel; string geometry; string keyboard; string kbtype; bool media; string agentServer; string agentUser; string agentPass; int cups; string key; bool encryption; bool fullscreen; bool virtualDesktop; string customCommand; }; struct NXSessionData { string sessionName; string sessionType; int cache; int images; string linkType; bool render; string backingstore; int imageCompressionMethod; int imageCompressionLevel; string geometry; string keyboard; string kbtype; bool media; string agentServer; string agentUser; string agentPass; int cups; string id; string key; bool encryption; bool fullscreen; bool virtualDesktop; string customCommand; bool suspended; int xRes; int yRes; int depth; int display; bool terminate; }; struct NXResumeData { int display; string sessionType; string sessionID; string options; int depth; string screen; string available; string sessionName; }; } // namespace #endif nxcl-0.9/lib/.svn/text-base/notQt.cpp.svn-base0000444000175000017500000003275010764221506017662 0ustar mjj29mjj29/*************************************************************************** notQt.cpp: A set of Qt like functionality, especially related to the starting of processes. ------------------- begin : June 2007 copyright : (C) 2007 Embedded Software Foundry Ltd. (U.K.) : Author: Sebastian James email : seb@esfnet.co.uk ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #include #include extern "C" { #include #include #include #include #include #include #include } #include "../config.h" #include "notQt.h" using namespace std; using namespace nxcl; /*! * Implementation of the notQProcess class */ //@{ // Used when dealing with pipes #define READING_END 0 #define WRITING_END 1 #define STDIN 0 #define STDOUT 1 #define STDERR 2 // Constructor notQProcess::notQProcess () : progName("unknown"), error (NOTQPROCNOERROR), pid(0), signalledStart(false) { // Set up the polling structs this->p = static_cast(malloc (2*sizeof (struct pollfd))); } // Destructor notQProcess::~notQProcess () { free (this->p); } void notQProcess::writeIn (string& input) { write (this->parentToChild[WRITING_END], input.c_str(), input.size()); } // fork and exec a new process using execv, which takes stdin via a // fifo and returns output also via a fifo. int notQProcess::start (const string& program, const list& args) { char** argarray; list myargs = args; list::iterator i; unsigned int j = 0; int theError; // NB: The first item in the args list should be the program name. this->progName = program; // Set up our pipes if (pipe(parentToChild) == -1 || pipe(childToParent) == -1 || pipe(childErrToParent) == -1) { return NOTQTPROCESS_FAILURE; } this->pid = fork(); switch (this->pid) { case -1: return NOTQTPROCESS_FAILURE; case 0: // This is the CHILD process // Close unwanted ends of the pipes close (parentToChild[WRITING_END]); close (childToParent[READING_END]); close (childErrToParent[READING_END]); // Now all we have to do is make the writing file // descriptors 0,1 or 2 and they will be used instead // of stdout, stderr and stdin. if ((dup2 (parentToChild[READING_END], STDIN)) == -1 || (dup2 (childToParent[WRITING_END], STDOUT)) == -1 || (dup2 (childErrToParent[WRITING_END], STDERR)) == -1) { theError = errno; cout << "ERROR! Couldn't get access to stdin/out/err! errno was " << theError << endl; return NOTQTPROCESS_FAILURE; } // Allocate memory for the program arguments // 1+ to allow space for NULL terminating pointer argarray = static_cast(malloc ((1+args.size()) * sizeof (char*))); for (i=myargs.begin(); i!=myargs.end(); i++) { argarray[j] = static_cast(malloc ( (1+(*i).size()) * sizeof (char) )); snprintf (argarray[j++], 1+(*i).size(), "%s", (*i).c_str()); dbgln(*i); } argarray[j] = NULL; dbgln ("About to execute '" + program + "' with those arguments.."); execv (program.c_str(), argarray); // If process returns, error occurred theError = errno; // This'll get picked up by parseResponse cout << "notQProcess error: " << this->pid << " crashed. errno:" << theError << endl; // This won't get picked up by the parent process. this->error = NOTQPROCCRASHED; // In this case, we close the pipes to signal to the parent that we crashed close (parentToChild[READING_END]); close (childToParent[WRITING_END]); close (childErrToParent[WRITING_END]); // Child should exit now. _exit(-1); default: // This is the PARENT process // Close unwanted ends of the pipes close (parentToChild[READING_END]); close (childToParent[WRITING_END]); close (childErrToParent[WRITING_END]); // Write to this->parentToChild[WRITING_END] to write to stdin of the child // Read from this->childToParent[READING_END] to read from stdout of child // Read from this->childErrToParent[READING_END] to read from stderr of child break; } return NOTQTPROCESS_MAIN_APP; } // If no pid after a while, return false. bool notQProcess::waitForStarted (void) { unsigned int i=0; while (this->pid == 0 && i<1000) { usleep (1000); i++; } if (this->pid>0) { dbgln ("The process started!"); this->callbacks->startedSignal (this->progName); this->signalledStart = true; return true; } else { this->error = NOTQPROCFAILEDTOSTART; this->callbacks->errorSignal (this->error); return false; } } // Send a TERM signal to the process. void notQProcess::terminate (void) { kill (this->pid, 15); // 15 is TERM // Now check if the process has gone and kill it with signal 9 (KILL) this->pid = 0; this->error = NOTQPROCNOERROR; this->signalledStart = false; return; } // Check on this process void notQProcess::probeProcess (void) { // Has the process started? if (!this->signalledStart) { if (this->pid > 0) { this->callbacks->startedSignal (this->progName); this->signalledStart = true; dbgln ("notQProcess::probeProcess set signalledStart and signalled the start..."); } } // Check for error condition if (this->error>0) { this->callbacks->errorSignal (this->error); dbgln ("have error in probeProcess, returning"); return; } if (this->pid == 0) { // Not yet started. return; } // Why can't these 4 lines go in contructor? this->p[0].fd = this->childToParent[READING_END]; this->p[0].events = POLLIN | POLLPRI; this->p[1].fd = this->childErrToParent[READING_END]; this->p[1].events = POLLIN | POLLPRI; // Poll to determine if data is available this->p[0].revents = 0; this->p[1].revents = 0; poll (this->p, 2, 0); if (this->p[0].revents & POLLNVAL || this->p[1].revents & POLLNVAL) { dbgln ("notQProcess::probeProcess: pipes closed, process must have crashed"); this->error = NOTQPROCCRASHED; this->callbacks->errorSignal (this->error); return; } if (this->p[0].revents & POLLIN || this->p[0].revents & POLLPRI) { this->callbacks->readyReadStandardOutputSignal(); } if (this->p[1].revents & POLLIN || this->p[1].revents & POLLPRI) { this->callbacks->readyReadStandardErrorSignal(); } // Is the process running? We check last, so that we get any // messages on stdout/stderr that we may wish to process, such // as error messages from nxssh key authentication. int theError; if (this->signalledStart == true) { int rtn = 0; if ((rtn = waitpid (this->pid, (int *)0, WNOHANG)) == this->pid) { this->callbacks->processFinishedSignal (this->progName); return; } else if (rtn == -1) { theError = errno; if (theError != 10) { // We ignore errno 10 "no child" as this commonly occurs cerr << "waitpid returned errno: " << theError; } } // else rtn == 0 } return; } // Read stdout pipe, without blocking. string notQProcess::readAllStandardOutput (void) { string s; int bytes = 0; char c; struct pollfd p; p.fd = this->childToParent[READING_END]; p.events = POLLIN | POLLPRI; // We know we have at least one character to read, so seed revents p.revents = POLLIN; while (p.revents & POLLIN || p.revents & POLLPRI) { // This read of 1 byte should never block if ((bytes = read (this->childToParent[READING_END], &c, 1)) == 1) { s.append (1, c); } p.revents = 0; poll (&p, 1, 0); } return s; } // Read stderr pipe without blocking string notQProcess::readAllStandardError (void) { string s; int bytes = 0; char c; struct pollfd p; p.fd = this->childErrToParent[READING_END]; p.events = POLLIN | POLLPRI; // We know we have at least one character to read, so seed revents p.revents = POLLIN; while (p.revents & POLLIN || p.revents & POLLPRI) { // This read of 1 byte should never block because a poll() call tells us there is data if ((bytes = read (this->childErrToParent[READING_END], &c, 1)) == 1) { s.append (1, c); } p.revents = 0; poll (&p, 1, 0); } return s; } //@} /*! * Implementation of the notQTemporaryFile class */ //@{ // Constructor notQTemporaryFile::notQTemporaryFile () { } // Destructor notQTemporaryFile::~notQTemporaryFile () { this->close(); } void notQTemporaryFile::open (void) { stringstream fn; fn << "/tmp/notQt" << time(NULL); this->theFileName = fn.str(); this->f.open (this->theFileName.c_str(), ios::in|ios::out|ios::trunc); } void notQTemporaryFile::write (string input) { this->f << input; } void notQTemporaryFile::close (void) { if (this->f.is_open()) { this->f.close(); } } // getter for fileName string notQTemporaryFile::fileName (void) { return this->theFileName; } void notQTemporaryFile::remove (void) { this->close(); unlink (this->theFileName.c_str()); } //@} /*! * Implementation of the notQtUtilities class */ //@{ // Constructor notQtUtilities::notQtUtilities () { } // Destructor notQtUtilities::~notQtUtilities () { } string notQtUtilities::simplify (string& input) { string workingString; unsigned int i=0, start, end; // Find the first non-whitespace character. while (input[i] != '\0' && (input[i] == ' ' || input[i] == '\t' || input[i] == '\n' || input[i] == '\r') && i0) { i--; } end = ++i; // Copy the substring into a working string. if (end>start) { workingString = input.substr (start, end-start); } else { return ""; } // Now we replace internal white spaces in workingString with single spaces. for (i=workingString.size(); i>1; --i) { if ( (workingString[i] == ' ' || workingString[i] == '\t' || workingString[i] == '\n' || workingString[i] == '\r') && (workingString[i-1] == ' ' || workingString[i-1] == '\t' || workingString[i-1] == '\n' || workingString[i-1] == '\r') ) { // ...then this is a whitespace we can remove workingString.erase(i,1); } else if ( (workingString[i] == '\t' || workingString[i] == '\n' || workingString[i] == '\r') && (workingString[i-1] != ' ' && workingString[i-1] != '\t' && workingString[i-1] != '\n' && workingString[i-1] != '\r') ) { // ...then this is a non-space whitespace to be replaced workingString.replace(i, 1, " "); } } return workingString; } // split based on token ' ' void notQtUtilities::splitString (string& line, char token, vector& rtn) { rtn.clear(); unsigned int i=0; while (i < (line.size())-1) { string tstring; while (line[i] && line[i] != token) { tstring.push_back(line[i++]); } rtn.push_back(tstring); i++; } return; } void notQtUtilities::splitString (string& line, char token, list& rtn) { rtn.clear(); unsigned int i=0; while (i < (line.size())-1) { string tstring; while (line[i] && line[i] != token) { //dbgln ("tstring.push_back line[i] which is '" << line[i] << "'"); tstring.push_back(line[i++]); } //dbgln ("rtn.push_back() tstring which is '" + tstring + "'"); rtn.push_back(tstring); i++; } return; } int notQtUtilities::ensureUnixNewlines (std::string& input) { int num = 0; for (unsigned int i=0; i #include "notQt.h" #include "nxclientlib.h" #include "nxsession.h" using namespace std; using namespace nxcl; NXSession::NXSession() : devurand_fd(-1), stage(HELLO_NXCLIENT), sessionDataSet(false), nxUsername("nouser"), nxPassword("nopass") { } NXSession::~NXSession() { } void NXSession::resetSession() { this->stage = 0; this->sessionDataSet = false; } string NXSession::parseSSH(string message) { dbgln ("NXSession::parseSSH called for: " + message); int response = parseResponse (message); string returnMessage; if (response == 211) { if (doSSH == true) { returnMessage = "yes"; doSSH = false; } else returnMessage = "no"; } if (response == 204) { // Authentication failed returnMessage = "204"; } if (response == 147) { // Server capacity reached returnMessage = "147"; this->stage = FINISHED; } switch (this->stage) { case HELLO_NXCLIENT: dbgln ("HELLO_NXCLIENT stage"); if (message.find("HELLO NXSERVER - Version") != string::npos) { this->callbacks->authenticatedSignal(); returnMessage = "hello NXCLIENT - Version "; returnMessage.append(CLIENT_VERSION); this->stage++; } break; case ACKNOWLEDGE: dbgln ("ACKNOWLEDGE stage"); if (response == 105) this->stage++; break; case SHELL_MODE: dbgln ("SHELL_MODE stage"); if (response == 105) { returnMessage = "SET SHELL_MODE SHELL"; this->stage++; } break; case AUTH_MODE: dbgln ("AUTH_MODE stage"); if (response == 105) { returnMessage = "SET AUTH_MODE PASSWORD"; this->stage++; } break; case LOGIN: dbgln ("LOGIN stage"); switch (response) { case 105: returnMessage = "login"; break; case 101: returnMessage = nxUsername; break; case 102: returnMessage = nxPassword; break; case 103: this->stage++; break; case 404: this->callbacks->loginFailedSignal(); } break; case LIST_SESSIONS: dbgln ("LIST_SESSIONS stage"); if (this->sessionData->terminate == true) { // Wait for termination dbgln ("Waiting for termination"); if (response == 900) { stringstream termsession; termsession << "NX> 900 Session id: " << this->sessionData->id << " terminated."; if (message.find (termsession.str().c_str(), 0) == 0) { // Session terminated. this->sessionData->terminate = false; } else { usleep (10000); } } } else if (response == 105) { // Get a list of the available sessions on the server, for // given user, with given status, and any type. Not sure if // geometry is ignored or not. stringstream ss; // We want to list suspended or running sessions, with this // command: dbgln ("this->resumeSessions.size() == " << this->resumeSessions.size()); if (this->sessionData->sessionType == "shadow") { // This is how to list shadow sessions. Run NoMachine's // client and see ~/.nx/temp/(pid)/sshlog for connection // details ss << "listsession --type=\"shadow\""; } else { ss << "listsession --user=\"" << nxUsername << "\" --status=\"suspended,running\" --geometry=\"" << this->sessionData->xRes << "x" << this->sessionData->yRes << "x" << this->sessionData->depth << (this->sessionData->render ? "+render" : "") // If you leave --type blank, you can re-connect to any // sessions available. << "\" --type=\"" << this->sessionData->sessionType << "\""; } returnMessage = ss.str(); this->stage++; } break; case PARSESESSIONS: dbgln ("PARSESESSIONS stage"); if ((this->sessionData->sessionType == "shadow" && response != 105) || (this->sessionData->sessionType != "shadow" && response != 148) ) { dbgln ("Building resumeSessions:" << " resumeSessions.push_back(message);"); this->resumeSessions.push_back(message); } else if ((this->sessionData->sessionType == "shadow" && response == 105) || (this->sessionData->sessionType != "shadow" && response == 148)) { dbgln ("Parsing resumeSessions:" << " parseResumeSessions(resumeSessions);"); parseResumeSessions (this->resumeSessions); dbgln ("parseResumeSessions(resumeSessions) returned"); // Now, the problem we have here, is that when // we return from the last 105 response, we // don't then get another stdout message to // act upon. So, we want to recurse back into // parseSSH to get onto the STARTSESSION stage here: returnMessage = this->parseSSH (message); } break; case STARTSESSION: dbgln ("STARTSESSION stage"); if (response == 105 && sessionDataSet) { dbgln ("response is 105 and sessionDataSet is true");; int media = 0; string fullscreen = ""; if (this->sessionData->media) { media = 1; } if (this->sessionData->fullscreen) { this->sessionData->geometry = "fullscreen"; fullscreen = "+fullscreen"; } if (this->sessionData->sessionType == "shadow" && this->sessionData->terminate == false) { dbgln ("It's a shadow session!"); stringstream ss; // These are the session parameters that NoMachine's client // sends for resume ss << "attachsession " << "--link=\"" << this->sessionData->linkType << "\" " << "--backingstore=\"" << this->sessionData->backingstore << "\" " << "--encryption=\"" << this->sessionData->encryption << "\" " << "--cache=\"" << this->sessionData->cache << "M\" " << "--images=\"" << this->sessionData->images << "M\" " // probably has been autodetected from my display << "--shmem=\"1\" " // probably has been autodetected from my display << "--shpix=\"1\" " // probably has been autodetected from my display << "--strict=\"0\" " // probably has been autodetected from my display << "--composite=\"1\" " << "--media=\"" << media << "\" " << "--session=\"" << this->sessionData->sessionName << "\" " << "--type=\"" << this->sessionData->sessionType << "\" " // FIXME: This may be some other OS if you compile it on // Sun, Windows, etc. << "--client=\"linux\" " << "--keyboard=\"" << this->sessionData->keyboard << "\" " << "--id=\"" << this->sessionData->id << "\" " // This may be the key? << "--display=\"0\" " << "--geometry=\"" << this->sessionData->geometry << "\" "; returnMessage = ss.str(); dbgln ("session parameter command: " + ss.str()); this->stage++; } else if (this->sessionData->terminate == true) { stringstream ss; // These are the session parameters that NoMachine's client // sends for resume ss << "Terminate --sessionid=\"" << this->sessionData->id << "\""; returnMessage = ss.str(); dbgln ("session parameter command: " + ss.str()); // Back to listsessions after terminating a session. this->stage -= 2; // Clear the list of sessions to resume this->resumeSessions.clear(); this->runningSessions.clear(); } else if (this->sessionData->suspended) { dbgln ("this->sessionData->suspended is true"); stringstream ss; // These are the session parameters that NoMachine's client // sends for resume ss << "restoresession --id=\"" << this->sessionData->id << "\" --session=\"" << this->sessionData->sessionName << "\" --type=\"" << this->sessionData->sessionType << "\" --cache=\"" << this->sessionData->cache << "M\" --images=\"" << this->sessionData->images << "M\" --cookie=\"" << generateCookie() << "\" --link=\"" << this->sessionData->linkType << "\" --kbtype=\"" << this->sessionData->kbtype << "\" --nodelay=\"1\" --encryption=\"" << this->sessionData->encryption << "\" --backingstore=\"" << this->sessionData->backingstore << "\" --geometry=\"" << this->sessionData->geometry << "\" --media=\"" << media << "\" --agent_server=\"" << this->sessionData->agentServer << "\" --agent_user=\"" << this->sessionData->agentUser << "\" --agent_password=\"" << this->sessionData->agentPass << "\""; returnMessage = ss.str(); dbgln ("session parameter command: " + ss.str()); this->stage++; } else { dbgln ("this->sessionData->suspended is false, and it's" << " not a shadow session."); stringstream ss; ss << "startsession --session=\"" << this->sessionData->sessionName << "\" --type=\"" << this->sessionData->sessionType << "\" --cache=\"" << this->sessionData->cache << "M\" --images=\"" << this->sessionData->images << "M\" --cookie=\"" << generateCookie() << "\" --link=\"" << this->sessionData->linkType << "\" --render=\"" << (this->sessionData->render ? 1 : 0) << "\" --encryption=\"" << this->sessionData->encryption << "\" --backingstore=\"" << this->sessionData->backingstore << "\" --imagecompressionmethod=\"" << this->sessionData->imageCompressionMethod << "\" --geometry=\"" << this->sessionData->geometry << "\" --screeninfo=\"" << this->sessionData->xRes << "x" << this->sessionData->yRes << "x" << this->sessionData->depth << (this->sessionData->render ? "+render" : "") << fullscreen << "\" --keyboard=\"" << this->sessionData->keyboard << "\" --kbtype=\"" << this->sessionData->kbtype << "\" --media=\"" << media << "\" --agent_server=\"" << this->sessionData->agentServer << "\" --agent_user=\"" << this->sessionData->agentUser << "\" --agent_password=\"" << this->sessionData->agentPass << "\""; ss << " --title=\"sebtest\""; // testing a window title if (this->sessionData->sessionType == "unix-application") { ss << " --application=\"" << this->sessionData->customCommand << "\""; if (this->sessionData->virtualDesktop == true) { ss << " --rootless=\"0\" --virtualdesktop=\"1\""; } else { ss << " --rootless=\"1\" --virtualdesktop=\"0\""; } } else if (this->sessionData->sessionType == "unix-console") { if (this->sessionData->virtualDesktop == true) { ss << " --rootless=\"0\" --virtualdesktop=\"1\""; } else { ss << " --rootless=\"1\" --virtualdesktop=\"0\""; } } else if (this->sessionData->sessionType == "unix-default") { // ignore this - does anyone use it? } returnMessage = ss.str(); dbgln ("session parameter command: " + ss.str()); this->stage++; } } else { dbgln ("either response is not 105 or sessionDataSet is" << " false."); } break; case FINISHED: dbgln ("FINISHED stage. Response is " << response << ". That should mean that session set up is complete."); this->callbacks->readyForProxySignal(); } dbgln ("NXSession::parseSSH, about to return a message: " + returnMessage); if (!returnMessage.empty()) { returnMessage.append("\n"); return returnMessage; } else return ""; } void NXSession::setSessionData (NXSessionData *sd) { this->sessionData = sd; } int NXSession::parseResponse(string message) { string::size_type idx1, idx2; int response; dbgln ("NXSession::parseResponse called for message:" << message); if ((idx1 = message.find ("notQProcess error", 0)) != string::npos) { dbgln ("Found notQProcess error"); // This means a process crashed, we're going to return a number >100000 // to indicate this. if ( ((idx2 = message.find ("crashed", 0)) != string::npos) && idx2 > idx1) { stringstream ss; ss << message.substr((idx1+19), idx2-1-(idx1+19)); // This is the pid that crashed ss >> response; // Add 100000 and return this response += 100000; return response; } else { dbgln ("Uh oh, didn't find \"crashed\""); } } // Find out the server response number // This will only be present in strings which contain "NX>" if (message.find("NX>") != string::npos && message.find("NX>") == 0) { idx1 = message.find("NX>") + 4; if ((idx2 = message.find(" ", idx1)) == string::npos) { if ((idx2 = message.find("\n", idx1)) == string::npos) { idx2 = message.size(); } } if (idx2>idx1) { stringstream ss; ss << message.substr(idx1, idx2-idx1); ss >> response; } else { response = 0; } } else { response = 0; } dbgln ("NXSession::parseResponse() returning " << response); return response; } void NXSession::parseResumeSessions(list rawdata) { // Was: QStringList sessions, and got rawdata appended to it? list sessions; list::iterator iter, at; dbgln ("NXSession::parseResumeSessions called."); for (iter = rawdata.begin(); iter != rawdata.end(); iter++) { if (((*iter).find("-------") != string::npos) && !(*iter).empty()) { at = iter; } } for (iter = ++at; iter != rawdata.end(); iter++) { if ((!(*iter).find("NX> 148") != string::npos) && !(*iter).empty()) { sessions.push_back(*iter); } } list < vector > rawsessions; list < vector >::iterator rsIter; // Clean up each string in sessions[i], then push back // sessions[i] onto rawsessions., except that means // rawsessions is then just a list... vector session; vector::iterator seshIter; for (iter = sessions.begin(); iter != sessions.end(); iter++) { session.clear(); // Simplify one line of list sessions (*iter) = notQtUtilities::simplify (*iter); // Split one line of list sessions into a vector notQtUtilities::splitString (*iter, ' ', session); // Add that to rawsessions rawsessions.push_back(session); } NXResumeData resData; for (rsIter = rawsessions.begin(); rsIter != rawsessions.end(); rsIter++) { stringstream ss1, ss2; int tmp; dbgln ("*rsIter.size() == " << (*rsIter).size()); ss1 << (*rsIter)[0]; ss1 >> tmp; resData.display = tmp; dbgln ("resData.display = " << resData.display); resData.sessionType = (*rsIter)[1]; dbgln ("resData.sessionType = " << resData.sessionType); resData.sessionID = (*rsIter)[2]; dbgln ("resData.sessionID = " << resData.sessionID); resData.options = (*rsIter)[3]; dbgln ("resData.options = " << resData.options); ss2 << (*rsIter)[4]; ss2 >> tmp; resData.depth = tmp; dbgln ("resData.depth = " << resData.depth); resData.screen = (*rsIter)[5]; dbgln ("resData.screen = " << resData.screen); resData.available = (*rsIter)[6]; dbgln ("resData.available = " << resData.available); resData.sessionName = (*rsIter)[7]; dbgln ("resData.sessionName = " << resData.sessionName); this->runningSessions.push_back(resData); } if (this->runningSessions.size() != 0) { this->suspendedSessions = true; dbgln ("NXSession::parseResumeSessions(): Calling sessionsSignal."); // runningSessions is a list of NXResumeData this->callbacks->sessionsSignal (this->runningSessions); } else { dbgln ("NXSession::parseResumeSessions(): Calling" << " this->callbacks->noSessionsSignal()"); // In case we previously had one resumable session, // which the user terminated, then we listsessions and // got no resumable sessions, we need to make sure // startsession is called, not restoresession. hence // set sessionData->suspended to false. this->sessionData->suspended = false; this->callbacks->noSessionsSignal(); } dbgln ("Increment stage"); this->stage++; dbgln ("NXSession::parseResumeSessions() returning."); } void NXSession::wipeSessions() { while (!this->runningSessions.empty()) { this->runningSessions.pop_front(); } } string NXSession::generateCookie() { unsigned long long int int1, int2; stringstream cookie; devurand_fd = open("/dev/urandom", O_RDONLY); fillRand((unsigned char*)&int1, sizeof(int1)); fillRand((unsigned char*)&int2, sizeof(int2)); cookie << int1 << int2; return cookie.str(); } void NXSession::fillRand(unsigned char *buf, size_t nbytes) { ssize_t r; unsigned char *where = buf; while (nbytes) { while ((r = read(devurand_fd, where, nbytes)) == -1) where += r; nbytes -= r; } } bool NXSession::chooseResumable (int n) { dbgln ("NXSession::chooseResumable called."); if (this->runningSessions.size() <= static_cast(n)) { // No nth session to resume. dbgln ("No nth session to resume, return false."); return false; } // Set to false while we change contents of sessionData this->sessionDataSet = false; list::iterator it = this->runningSessions.begin(); for (int i = 0; isessionData->sessionType != "shadow") { this->sessionData->sessionType = (*it).sessionType; } this->sessionData->display = (*it).display; this->sessionData->sessionName = (*it).sessionName; this->sessionData->id = (*it).sessionID; stringstream geom; // Plus render, if necessary geom << (*it).screen << "x" << (*it).display; // FIXME: This not yet quite complete. // With depth in there too? this->sessionData->geometry = geom.str(); this->sessionData->suspended=true; this->sessionDataSet = true; dbgln ("NXSession::chooseResumable returning true."); return true; } bool NXSession::terminateSession (int n) { dbgln ("NXSession::terminateSession called."); if (this->runningSessions.size() <= static_cast(n)) { // No nth session to terminate dbgln ("No nth session to terminate, return false."); return false; } // Set to false while we change the contents of sessionData this->sessionDataSet = false; list::iterator it = this->runningSessions.begin(); for (int i = 0; isessionData->terminate = true; this->sessionData->display = (*it).display; this->sessionData->sessionName = (*it).sessionName; this->sessionData->id = (*it).sessionID; this->sessionData->suspended=true; this->sessionDataSet = true; return true; } nxcl-0.9/lib/.svn/text-base/notQt.h.svn-base0000444000175000017500000001450210764221506017322 0ustar mjj29mjj29/* -*-c++-*- */ /*************************************************************************** notQt.h: A set of Qt like functionality, especially related to the starting of processes. ------------------- begin : June 2007 copyright : (C) 2007 Embedded Software Foundry Ltd. (U.K.) : Author: Sebastian James email : seb@esfnet.co.uk ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ /*! * \file notQt.h Simple re-implementations of some Qt-like * functionality. In particular, there's a QProcess-like (though much * simplified) class, a QTemporaryFile like class and a couple of the * methods that you get with QString. */ #ifndef _NOTQT_H_ #define _NOTQT_H_ #include #include #include #include extern "C" { #include } #define NOTQTPROCESS_MAIN_APP 0 #define NOTQTPROCESS_FAILURE -1 // Possible errors to be generated #define NOTQPROCNOERROR 0 #define NOTQPROCFAILEDTOSTART 1 #define NOTQPROCCRASHED 2 #define NOTQPROCTIMEDOUT 3 #define NOTQPROCWRITEERR 4 #define NOTQPROCREADERR 5 #define NOTQPROCUNKNOWN 6 using namespace std; #ifdef DEBUG extern ofstream debugLogFile; # define dbgln(msg) debugLogFile << __FUNCTION__ << ": " << msg << endl; # define dbglln(msg) debugLogFile << __PRETTY_FUNCTION__ << ": " << msg << endl; # define dbg(msg) debugLogFile << msg; #else # define dbgln(msg) # define dbglln(msg) # define dbg(msg) #endif namespace nxcl { /*! * A set of virtual callbacks. These should be derived in the * client code. They're called by notQProcess via the * notQProcessCallbacks* callbacks member variable. */ class notQProcessCallbacks { public: notQProcessCallbacks() {} virtual ~notQProcessCallbacks() {} virtual void startedSignal (string) {} virtual void errorSignal (int) {} virtual void processFinishedSignal (string) {} virtual void readyReadStandardOutputSignal (void) {} virtual void readyReadStandardErrorSignal (void) {} }; /*! * notQProcess is a simple replacement for the Qt class QProcess. */ class notQProcess { public: notQProcess(); ~notQProcess(); /*! * Write \arg input to the stdin of the process. */ void writeIn (string& input); /*! * fork and exec the process. */ int start (const string& program, const list& args); /*! * Send a TERM signal to the process. */ void terminate (void); /*! * poll to see if there is data on stderr or stdout * and to see if the process has exited. * * This must be called on a scheduled basis. It checks * for any stdout/stderr data and also checks whether * the process is still running. */ void probeProcess (void); /*! * Accessors */ //@{ pid_t getPid (void) { return this->pid; } int getError (void) { return this->error; } void setError (int e) { this->error = e; } /*! * Setter for the callbacks. */ void setCallbacks (notQProcessCallbacks * cb) { this->callbacks = cb; } //@} /*! * Slots */ //@{ string readAllStandardOutput (void); string readAllStandardError (void); /*! * Wait for the process to get itself going. Do this * by looking at pid. If no pid after a while, * return false. */ bool waitForStarted (void); //@} private: /*! * The name of the program to execute */ string progName; /*! * The environment and arguments of the program to execute */ list environment; /*! * Holds a notQProcess error, defined above. NOTQPROCNOERROR, etc. */ int error; /*! * Process ID of the program */ pid_t pid; /*! * Set to true if the fact that the program has been * started has been signalled using the callback * callbacks->startedSignal */ bool signalledStart; /*! * stdin parent to child */ int parentToChild[2]; /*! * stdout child to parent */ int childToParent[2]; /*! * stderr child to parent */ int childErrToParent[2]; /*! * Used in the poll() call in probeProcess() */ struct pollfd * p; /*! * Pointer to a callback object */ notQProcessCallbacks * callbacks; }; /*! * A simple replacement for the Qt Class QTemporaryFile. */ class notQTemporaryFile { public: notQTemporaryFile(); ~notQTemporaryFile(); /*! * Open a file with a (not really) random name. The * filename will be /tmp/notQtXXXXXX where XXXXXX will * be the time in seconds since the unix epoch. */ void open (void); /*! * Write \arg input to the temporary file. */ void write (string input); /*! * Close the temporary file's stream. */ void close (void); /*! * A getter for the file name of the temporary file */ string fileName (void); /*! * Remove the temporary file */ void remove (void); private: /*! * The file name of the temporary file */ string theFileName; /*! * The file stream for the temporary file */ fstream f; }; /*! * A few useful utility functions. */ class notQtUtilities { public: notQtUtilities(); ~notQtUtilities(); /*! The same (more or less) as Qt QString::simplified */ static string simplify (string& input); /*! * Split a string 'line' based on token, placing the portions in the vector rtn */ static void splitString (string& line, char token, vector& rtn); /*! * Split a string 'line' based on token, placing the portions in the list rtn */ static void splitString (string& line, char token, list& rtn); /*! * Run through input and replace any DOS newlines with unix newlines. */ static int ensureUnixNewlines (std::string& input); }; } // namespace #endif nxcl-0.9/lib/.svn/text-base/nxclientlib.cpp.svn-base0000444000175000017500000006507210764221506021073 0ustar mjj29mjj29/*************************************************************************** nxclientlib.cpp ------------------- begin : Sat 22nd July 2006 modifications : July 2007 copyright : (C) 2006 by George Wright modifications : (C) 2007 Embedded Software Foundry Ltd. (U.K.) : Author: Sebastian James : (C) 2008 Defuturo Ltd : Author: George Wright email : seb@esfnet.co.uk, gwright@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #include "nxclientlib_i18n.h" #include "nxclientlib.h" #include "nxdata.h" #include "../config.h" #include extern "C" { #include #include #include #include } /* * On the location of nxproxy and nxssh binaries * --------------------------------------------- * We expect them to be installed in PACKAGE_BIN_DIR (See * Makefile.am). So, if nxcl is installed in /usr/bin/nxcl then we * call /usr/bin/nxssh and /usr/bin/nxproxy, etc etc. */ using namespace std; using namespace nxcl; /*! * Implementation of the NXClientLibCallbacks class */ //@{ NXClientLibCallbacks::NXClientLibCallbacks() { } NXClientLibCallbacks::~NXClientLibCallbacks() { } void NXClientLibCallbacks::startedSignal (string name) { this->parent->externalCallbacks->write (NXCL_PROCESS_STARTED, name + _(" process started")); } void NXClientLibCallbacks::processFinishedSignal (string name) { this->parent->externalCallbacks->write (NXCL_PROCESS_EXITED, name + _(" process exited")); parent->setIsFinished (true); } void NXClientLibCallbacks::errorSignal (int error) { string message; switch (error) { case NOTQPROCFAILEDTOSTART: message = _("The process failed to start"); break; case NOTQPROCCRASHED: message = _("The process has crashed"); break; case NOTQPROCTIMEDOUT: message = _("The process timed out"); break; case NOTQPROCWRITEERR: message = _("There was an error writing to the process"); break; case NOTQPROCREADERR: message = _("There was an error reading from the process"); break; default: message = _("There was an unknown error with the process"); break; } this->parent->externalCallbacks->error (message); } void NXClientLibCallbacks::readyReadStandardOutputSignal() { this->parent->processParseStdout(); } void NXClientLibCallbacks::readyReadStandardErrorSignal() { this->parent->processParseStderr(); } /*! * This gets called from within the NXSession object... */ void NXClientLibCallbacks::noSessionsSignal() { this->parent->externalCallbacks->noSessionsSignal(); } void NXClientLibCallbacks::loginFailedSignal() { this->parent->loginFailed(); } void NXClientLibCallbacks::readyForProxySignal() { this->parent->readyproxy(); } void NXClientLibCallbacks::authenticatedSignal() { this->parent->doneAuth(); } void NXClientLibCallbacks::sessionsSignal (list data) { this->parent->externalCallbacks->resumeSessionsSignal (data); } //@} /*!e * Implementation of the NXClientLib class */ //@{ NXClientLib::NXClientLib() : nxsshProcess(new notQProcess()), nxproxyProcess(new notQProcess()), x11Process(new notQProcess()), nxauthProcess(new notQProcess()) { this->isFinished = false; this->readyForProxy = false; this->sessionRunning = false; this->proxyData.encrypted = false; this->password = false; dbgln ("In NXClientLib constructor"); /* Set up callback pointers */ this->nxsshProcess->setCallbacks (&callbacks); this->nxproxyProcess->setCallbacks (&callbacks); this->x11Process->setCallbacks (&callbacks); this->nxauthProcess->setCallbacks (&callbacks); this->session.setCallbacks (&callbacks); this->callbacks.setParent (this); dbgln ("Returning from NXClientLib constructor"); } NXClientLib::~NXClientLib() { dbgln ("In NXClientLib destructor"); } void NXClientLib::invokeNXSSH (string publicKey, string serverHost, bool encryption, string key, int port) { list arguments; stringstream argtmp; proxyData.server = serverHost; dbgln("invokeNXSSH called"); // We use same environment for the process as was used for the // parent, so remove nxsshProcess->setEnvironment(); // Start to build the arguments for the nxssh command. // notQProcess requires that argv[0] contains the program name arguments.push_back ("nxssh"); argtmp << "-nx"; arguments.push_back (argtmp.str()); argtmp.str(""); argtmp << "-p" << port; arguments.push_back (argtmp.str()); if (publicKey == "supplied") { this->keyFile = new notQTemporaryFile; this->keyFile->open(); argtmp.str(""); argtmp << "-i" << this->keyFile->fileName(); arguments.push_back (argtmp.str()); this->keyFile->write (key); this->keyFile->close(); } else { this->keyFile = NULL; argtmp.str(""); argtmp << "-i" << publicKey; arguments.push_back (argtmp.str()); } argtmp.str(""); argtmp << "nx@" << serverHost; arguments.push_back (argtmp.str()); // These options copied from the way Nomachine's client // specifies the nxssh command - they make good sense. arguments.push_back ("-x"); arguments.push_back ("-2"); arguments.push_back ("-oRhostsAuthentication no"); arguments.push_back ("-oPasswordAuthentication no"); arguments.push_back ("-oRSAAuthentication no"); arguments.push_back ("-oRhostsRSAAuthentication no"); arguments.push_back ("-oPubkeyAuthentication yes"); if (encryption == true) { arguments.push_back("-B"); session.setEncryption (true); } else { session.setEncryption (false); } // -E appears in the call to nxssh for Nomachine's nxclient // -version 3 but not 1.5. Is it there in 2? // nxssh -E gives this message when called: // NX> 285 Enabling skip of SSH config files // ...so there you have the meaning. arguments.push_back ("-E"); // Find a path for the nxssh process using getPath() string nxsshPath = this->getPath ("nxssh"); this->nxsshProcess->start(nxsshPath, arguments); if (this->nxsshProcess->waitForStarted() == false) { this->externalCallbacks->write (NXCL_PROCESS_ERROR, _("Error starting nxssh!")); this->isFinished = true; } } void NXClientLib::requestConfirmation (string msg) { this->externalCallbacks->stdoutSignal (_("This is a placeholder method to deal with sending " "back a yes or a no answer. " "For now, we just set this->session.setContinue(true);")); this->session.setContinue(true); } void NXClientLib::reset() { this->nxsshProcess->terminate(); this->isFinished = false; this->proxyData.encrypted = false; this->password = false; this->session.resetSession(); } void NXClientLib::loginFailed() { this->externalCallbacks->write (NXCL_LOGIN_FAILED, _("Got \"Login Failed\"")); this->isFinished = true; this->nxsshProcess->terminate(); } void NXClientLib::processParseStdout() { string message = nxsshProcess->readAllStandardOutput(); this->externalCallbacks->stdoutSignal (message); dbgln ("NXClientLib::processParseStdout() called"); int response = 0; // Message 211 is sent if ssh is asking to continue with an unknown host if ((response = session.parseResponse(message)) == 211) { this->requestConfirmation (message); } dbgln ("NXClientLib::processParseStdout(): response = " << response); if (response == 100000) { // A program never started. this->isFinished = true; return; } else if (response > 100000) { dbgln ("A process crashed or exited"); int pid = response - 100000; if (this->nxsshProcess->getPid() == pid) { this->nxsshProcess->setError(NOTQPROCCRASHED); this->externalCallbacks->error (_("nxsshProcess crashed or exited")); this->isFinished = true; } else if (this->nxproxyProcess->getPid() == pid) { this->nxproxyProcess->setError(NOTQPROCCRASHED); this->externalCallbacks->error (_("nxproxyProcess crashed or exited")); this->isFinished = true; } else { this->externalCallbacks->error (_("Warning: Don't know what crashed " "(in processParseStdout())")); } return; } // If message 204 is picked, that's authentication failed. if (response == 204) { this->externalCallbacks->write (NXCL_AUTH_FAILED, _("Got \"Authentication Failed\" from nxssh.\n" "Please check the certificate for the first SSL " "authentication stage,\n" "in which the \"nx\" user is authenticated.")); this->isFinished = true; return; } // 147 is server capacity reached if (response == 147) { this->externalCallbacks->serverCapacitySignal(); this->isFinished = true; return; } dbgln ("NXClientLib::processParseStdout(): The message is '" + message + "'(msg end)"); dbgln ("...and response is " << response); notQtUtilities::ensureUnixNewlines (message); list msglist; list::iterator msgiter; notQtUtilities::splitString (message, '\n', msglist); for (msgiter = msglist.begin(); msgiter != msglist.end(); msgiter++) { dbgln ("NXClientLib::processParseStdout(): Processing the message '" + (*msgiter) + "'(end msg)"); // On some connections this is sent via stdout instead of stderr? if (proxyData.encrypted && readyForProxy && ((*msgiter).find("NX> 999 Bye")!=string::npos)) { // This is "NX> 299 Switching connection to: " in // version 1.5.0. This was changed in nxssh version // 2.0.0-8 (see the nxssh CHANGELOG). string switchCommand = "NX> 299 Switch connection to: "; stringstream ss; ss << "127.0.0.1:" << proxyData.port << " cookie: " << proxyData.cookie << "\n"; switchCommand += ss.str(); this->write (switchCommand); } else if ((*msgiter).find ("NX> 287 Redirected I/O to channel descriptors") != string::npos) { this->externalCallbacks->write (287, _("The session has been started successfully")); this->externalCallbacks->connectedSuccessfullySignal(); this->sessionRunning = true; } if ((*msgiter).find("Password") != string::npos) { this->externalCallbacks->write (NXCL_AUTHENTICATING, _("Authenticating with NX server")); this->password = true; } if (!readyForProxy) { string msg = session.parseSSH (*msgiter); if (msg == "204\n" || msg == "147\n") { // Auth failed. dbgln ("NXClientLib::processParseStdout: Got auth failed" " or capacity reached, calling this->parseSSH."); msg = this->parseSSH (*msgiter); } if (msg.size() > 0) { this->write (msg); } } else { this->write (this->parseSSH (*msgiter)); } } return; } void NXClientLib::processParseStderr() { string message = nxsshProcess->readAllStandardError(); dbgln ("In NXClientLib::processParseStderr for message: '" + message + "'(msg end)"); this->externalCallbacks->stderrSignal (message); // Now we need to split the message if necessary based on the // \n or \r characters notQtUtilities::ensureUnixNewlines (message); list msglist; list::iterator msgiter; notQtUtilities::splitString (message, '\n', msglist); for (msgiter=msglist.begin(); msgiter!=msglist.end(); msgiter++) { dbgln ("NXClientLib::processParseStderr: Processing the message '" + (*msgiter) + "'(end msg)"); if (proxyData.encrypted && readyForProxy && ((*msgiter).find("NX> 999 Bye") != string::npos)) { string switchCommand = "NX> 299 Switch connection to: "; stringstream ss; ss << "127.0.0.1:" << proxyData.port << " cookie: " << proxyData.cookie << "\n"; switchCommand += ss.str(); this->write(switchCommand); } else if ((*msgiter).find ("NX> 287 Redirected I/O to channel descriptors") != string::npos) { this->externalCallbacks->write (287, _("The session has been started successfully")); this->externalCallbacks->connectedSuccessfullySignal(); } else if ((*msgiter).find ("NX> 209 Remote host identification has changed") != string::npos) { this->externalCallbacks->write(209, _("SSH Host Key Problem")); this->isFinished = true; } else if ((*msgiter).find ("NX> 280 Ignoring EOF on the monitored channel") != string::npos) { this->externalCallbacks->write (280, _("Got \"NX> 280 Ignoring EOF on the monitored channel\"" " from nxssh...")); this->isFinished = true; } else if ((*msgiter).find ("Host key verification failed") != string::npos) { this->externalCallbacks->write (NXCL_HOST_KEY_VERIFAILED, _("SSH host key verification failed")); this->isFinished = true; } } } void NXClientLib::write (string data) { if (data.size() == 0) { return; } dbgln ("Writing '" << data << "' to nxssh process."); this->nxsshProcess->writeIn(data); if (password) { data = "********"; password = false; } // Output this to the user via a signal - this is data going in to nxssh. this->externalCallbacks->stdinSignal (data); } void NXClientLib::doneAuth() { if (this->keyFile != NULL) { this->keyFile->remove(); delete this->keyFile; } return; } void NXClientLib::allowSSHConnect (bool auth) { session.setContinue (auth); } void NXClientLib::setSessionData (NXSessionData *nxSessionData) { session.setSessionData (nxSessionData); string a = "NX> 105"; string d = session.parseSSH(a); if (d.size()>0) { this->write(d); } } void NXClientLib::runSession () { session.runSession(); string a = "NX> 105"; string d = session.parseSSH(a); if (d.size()>0) { this->write(d); } } string NXClientLib::parseSSH (string message) { string rMessage; string::size_type pos; rMessage = ""; dbgln ("NXClientLib::parseSSH called for message '" + message + "'"); if ((pos = message.find("NX> 700 Session id: ")) != string::npos) { this->externalCallbacks->write (700, _("Got a session ID")); proxyData.id = message.substr(pos+20, message.length()-pos); } else if ((pos = message.find("NX> 705 Session display: ")) != string::npos) { stringstream portss; int portnum; portss << message.substr(pos+25, message.length()-pos); portss >> portnum; proxyData.display = portnum; proxyData.port = portnum + 4000; } else if ((pos = message.find("NX> 706 Agent cookie: ")) != string::npos) { proxyData.cookie = message.substr(pos+22, message.length()-pos); this->externalCallbacks->write (706, _("Got an agent cookie")); } else if ((pos = message.find("NX> 702 Proxy IP: ")) != string::npos) { proxyData.proxyIP = message.substr(pos+18, message.length()-pos); this->externalCallbacks->write (702, _("Got a proxy IP")); } else if (message.find("NX> 707 SSL tunneling: 1") != string::npos) { this->externalCallbacks->write (702, _("All data will be SSL tunnelled")); proxyData.encrypted = true; } else if (message.find("NX> 147 Server capacity") != string::npos) { this->externalCallbacks->write (147, _("Got \"Server Capacity Reached\" from nxssh.")); this->externalCallbacks->serverCapacitySignal(); this->isFinished = true; } else if (message.find ("NX> 204 Authentication failed.") != string::npos) { this->externalCallbacks->write (204, _("NX SSH Authentication Failed, finishing")); this->isFinished = true; } if (message.find("NX> 710 Session status: running") != string::npos) { this->externalCallbacks->write (710, _("Session status is \"running\"")); invokeProxy(); session.wipeSessions(); rMessage = "bye\n"; } return rMessage; } void NXClientLib::invokeProxy() { this->externalCallbacks->write (NXCL_INVOKE_PROXY, _("Starting NX session")); #if NXCL_CYGWIN NXSessionData* sessionData = getSession()->getSessionData(); string res; if (sessionData->geometry == "fullscreen") { stringstream resolution; ostringstream dimensionX, dimensionY; dimensionX << sessionData->xRes; dimensionY << sessionData->yRes; resolution << dimensionX.str() << "x" << dimensionY.str(); res = resolution.str(); } else { res = sessionData->geometry; } startX11(res, ""); #endif #if NXCL_DARWIN // Let's run open -a X11 to fire up X list x11Arguments; x11Arguments.push_back("open"); x11Arguments.push_back("-a"); x11Arguments.push_back("X11"); string openPath = this->getPath("open"); this->x11Process->start(openPath, x11Arguments); this->x11Probe = true; if (this->x11Process->waitForStarted() == false) { this->externalCallbacks->write (NXCL_PROCESS_ERROR, _("Error starting X11!")); this->isFinished = true; } this->x11Probe = false; // Horrendous hack - must fix for (int i = 0; i < 32768; i++) {}; #endif int e; char * home; home = getenv ("HOME"); stringstream ss; ss << home; string nxdir = ss.str(); nxdir += "/.nx"; // Create the .nx directory first. if (mkdir (nxdir.c_str(), 0770)) { e = errno; if (e != EEXIST) { // We don't mind .nx already // existing, though if there is a // _file_ called $HOME/.nx, we'll // get errors later. this->externalCallbacks->error (_("Problem creating .nx directory")); } } // Now the per session directory nxdir += "/S-" + proxyData.id; if (mkdir (nxdir.c_str(), 0770)) { e = errno; if (e != EEXIST) { // We don't mind .nx already this->externalCallbacks->error (_("Problem creating Session directory")); } } string x11Display = ""; #if NXCL_DARWIN || NXCL_CYGWIN x11Display = ",display=:0.0"; #endif stringstream data; if (proxyData.encrypted) { data << "nx/nx" << x11Display << ",session=session,encryption=1,cookie=" << proxyData.cookie << ",id=" << proxyData.id << ",listen=" << proxyData.port << ":" << proxyData.display << "\n"; // may also need shmem=1,shpix=1,font=1,product=... } else { // Not tested yet data << "nx/nx" << x11Display << ",session=session,cookie=" << proxyData.cookie << ",id=" << proxyData.id // << ",connect=" << proxyData.server << ":" << proxyData.display << ",listen=" << proxyData.port << ":" << proxyData.display << "\n"; } // Filename is nxdir plus "/options" nxdir += "/options"; std::ofstream options; options.open (nxdir.c_str(), std::fstream::out); options << data.str(); options.close(); // Build arguments for the call to the nxproxy command list arguments; arguments.push_back("nxproxy"); // argv[0] has to be the program name arguments.push_back("-S"); ss.str(""); ss << "options=" << nxdir; ss << ":" << proxyData.display; arguments.push_back(ss.str()); // Find a path for the nxproxy process using getPath() string nxproxyPath = this->getPath ("nxproxy"); this->nxproxyProcess->start(nxproxyPath, arguments); if (this->nxproxyProcess->waitForStarted() == false) { this->externalCallbacks->write (NXCL_PROCESS_ERROR, _("Error starting nxproxy!")); this->isFinished = true; } } void NXClientLib::startX11 (string resolution, string name) { #if NXCL_CYGWIN // Invoke NXWin.exe on Windows machines // See if XAUTHORITY path is set stringstream xauthority; xauthority << getenv("HOME") << "/.Xauthority"; // Now we set the environment variable setenv("XAUTHORITY", xauthority.str().c_str(), 1); // Now we actually start NXWin.exe list nxwinArguments; // Arguments taken from 2X nxwinArguments.push_back("NXWin"); nxwinArguments.push_back("-nowinkill"); nxwinArguments.push_back("-clipboard"); nxwinArguments.push_back("-noloadxkb"); nxwinArguments.push_back("-agent"); nxwinArguments.push_back("-hide"); nxwinArguments.push_back("-noreset"); nxwinArguments.push_back("-nolisten"); nxwinArguments.push_back("tcp"); // TODO: If rootless, append "-multiwindow" and "-hide" but only // hide if not restoring // Now we set up the font paths. By default this is $NX_SYSTEM/usr/X11R6/... stringstream fontPath; fontPath << getenv("NX_SYSTEM") << "/X11R6/lib/X11/fonts/base," << getenv("NX_SYSTEM") << "/X11R6/lib/X11/fonts/TTF"; nxwinArguments.push_back("-fp"); nxwinArguments.push_back(fontPath.str()); nxwinArguments.push_back("-name"); nxwinArguments.push_back("NXWin"); nxwinArguments.push_back(":0"); nxwinArguments.push_back("-screen"); nxwinArguments.push_back("0"); nxwinArguments.push_back(resolution); nxwinArguments.push_back(":0"); nxwinArguments.push_back("-nokeyhook"); string nxwinPath = this->getPath("nxwin"); this->x11Process->start(nxwinPath, nxwinArguments); this->x11Probe = true; if (this->x11Process->waitForStarted() == false) { this->externalCallbacks->write (NXCL_PROCESS_ERROR, _("Error starting nxwin!")); this->isFinished = true; } this->x11Probe = false; list nxauthArguments; char hostname[256]; gethostname(hostname, 256); string cookie = getSession()->generateCookie(); cookie.resize(32); stringstream domain; domain << hostname << "/unix:0"; // These arguments taken from the 2X GPL client // We're going to assume that nxauth is in PATH nxauthArguments.push_back("nxauth"); nxauthArguments.push_back("-i"); nxauthArguments.push_back("-f"); nxauthArguments.push_back(xauthority.str()); nxauthArguments.push_back("add"); nxauthArguments.push_back(domain.str()); nxauthArguments.push_back("MIT-MAGIC-COOKIE-1"); nxauthArguments.push_back(cookie); this->nxauthProcess->setCallbacks (&callbacks); string nxauthPath = this->getPath("nxauth"); this->nxauthProcess->start(nxauthPath, nxauthArguments); if (this->nxauthProcess->waitForStarted() == false) { this->externalCallbacks->write (NXCL_PROCESS_ERROR, _("Error starting nxauth!")); this->isFinished = true; } #endif } bool NXClientLib::chooseResumable (int n) { return (this->session.chooseResumable(n)); } bool NXClientLib::terminateSession (int n) { return (this->session.terminateSession(n)); } string NXClientLib::getPath (string prog) { string path; struct stat * buf; buf = static_cast(malloc (sizeof (struct stat))); if (!buf) { // Malloc error. return prog; } // We'll check the custom search path first stringstream pathTest; pathTest << customPath << "/" << prog; memset (buf, 0, sizeof(struct stat)); stat (pathTest.str().c_str(), buf); if (S_ISREG (buf->st_mode) || S_ISLNK (buf->st_mode)) { // Found in custom path free(buf); return pathTest.str(); } path = PACKAGE_BIN_DIR"/" + prog; memset (buf, 0, sizeof(struct stat)); stat (path.c_str(), buf); if (S_ISREG (buf->st_mode) || S_ISLNK (buf->st_mode)) { // Found prog in PACKAGE_BIN_DIR } else { path = "/usr/local/bin/" + prog; memset (buf, 0, sizeof(struct stat)); stat (path.c_str(), buf); if (S_ISREG (buf->st_mode) || S_ISLNK (buf->st_mode)) { // Found prog in /usr/local/bin } else { path = "/usr/bin/" + prog; memset (buf, 0, sizeof(struct stat)); stat (path.c_str(), buf); if (S_ISREG (buf->st_mode) || S_ISLNK (buf->st_mode)) { // Found prog in /usr/bin } else { path = "/usr/NX/bin/" + prog; memset (buf, 0, sizeof(struct stat)); stat (path.c_str(), buf); if (S_ISREG (buf->st_mode) || S_ISLNK (buf->st_mode)) { } else { path = "/bin/" + prog; memset (buf, 0, sizeof(struct stat)); stat (path.c_str(), buf); if (S_ISREG (buf->st_mode) || S_ISLNK (buf->st_mode)) { // Found prog in /bin } else { // Just return the // prog name. path = prog; } } } } } free (buf); return path; } //@} nxcl-0.9/lib/.svn/prop-base/0000755000175000017500000000000010764221506014323 5ustar mjj29mjj29nxcl-0.9/lib/.svn/props/0000755000175000017500000000000010764221506013576 5ustar mjj29mjj29nxcl-0.9/lib/.svn/tmp/0000755000175000017500000000000010764221506013233 5ustar mjj29mjj29nxcl-0.9/lib/.svn/tmp/text-base/0000755000175000017500000000000010764221506015127 5ustar mjj29mjj29nxcl-0.9/lib/.svn/tmp/prop-base/0000755000175000017500000000000010764221506015123 5ustar mjj29mjj29nxcl-0.9/lib/.svn/tmp/props/0000755000175000017500000000000010764221506014376 5ustar mjj29mjj29nxcl-0.9/lib/.svn/entries0000444000175000017500000000267110764221506014033 0ustar mjj29mjj298 dir 500 svn://svn.berlios.de/freenx/tags/nxcl-0.9/lib svn://svn.berlios.de/freenx 2008-02-13T04:18:20.777348Z 476 gwright svn:special svn:externals svn:needs-lock 80778403-ebee-0310-8e0a-e86a689f3fff nxsession.h file 2008-03-07T11:13:10.000000Z 04aa5db1bf2d7aff1b4ff7fdfd0e7619 2008-01-29T14:56:58.303212Z 448 gwright nxclientlib_i18n.h file 2008-03-07T11:13:10.000000Z df9359150d3be01017ee3cdb0dc8e035 2007-09-11T12:48:46.240816Z 373 sebjames nxclientlib.h file 2008-03-07T11:13:10.000000Z 9919ab02281a1693f0d18d725473d629 2008-02-05T01:48:43.196166Z 467 gwright i18n.h file 2008-03-07T11:13:10.000000Z 05c327de2136f0b297d8873c6fac7fc8 2007-09-11T12:48:46.240816Z 373 sebjames nxdata.h file 2008-03-07T11:13:10.000000Z 5ce756b6e49f2ce89e2f531977d32e63 2007-09-17T20:50:22.245535Z 384 sebjames notQt.cpp file 2008-03-07T11:13:10.000000Z 6b564d6e859f360cc40a4ccbf3c8750d 2008-02-05T00:52:02.893088Z 460 gwright Makefile.am file 2008-03-07T11:13:10.000000Z a96a4e290ae1a514167f5db31cde4fc3 2008-01-30T07:57:35.836436Z 456 gwright nxsession.cpp file 2008-03-07T11:13:10.000000Z affa4317cdd84e1375c175e1dc60e24b 2008-01-07T12:10:22.170881Z 433 gwright notQt.h file 2008-03-07T11:13:10.000000Z 354ef685cfe51fd52feec4690e966250 2008-01-08T11:02:07.392330Z 436 gwright nxclientlib.cpp file 2008-03-07T11:13:10.000000Z ba4b9ec83f114821347a18b08fee8b38 2008-02-13T04:18:20.777348Z 476 gwright nxcl-0.9/lib/.svn/format0000444000175000017500000000000210764221506013634 0ustar mjj29mjj298 nxcl-0.9/lib/nxsession.h0000644000175000017500000001357310764221506013762 0ustar mjj29mjj29/*************************************************************************** nxsession.h ------------------- begin : Sat 22nd July 2006 modifications : July 2007 copyright : (C) 2006 by George Wright modifications : (C) 2007 Embedded Software Foundry Ltd. (U.K.) : Author: Sebastian James : (C) 2008 Defuturo Ltd : Author: George Wright email : seb@esfnet.co.uk, gwright@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #ifndef _NXSESSION_H_ #define _NXSESSION_H_ #include #include #include #include #include "nxdata.h" #include namespace nxcl { /*! * Virtual Callback class. These callbacks are called based on * the output which we get from the nxssh process. */ class NXSessionCallbacks { public: NXSessionCallbacks() {} virtual ~NXSessionCallbacks() {} virtual void noSessionsSignal (void) {} virtual void loginFailedSignal (void) {} virtual void readyForProxySignal (void) {} /*! * Emitted when the initial public key authentication * is successful */ virtual void authenticatedSignal (void) {} virtual void sessionsSignal (list) {} }; /*! * This class is used to parse the output from the nxssh * session to the server. */ class NXSession { public: NXSession(); ~NXSession(); string parseSSH (string); int parseResponse (string); void parseResumeSessions (list); void resetSession (void); void wipeSessions (void); bool chooseResumable (int n); bool terminateSession (int n); string generateCookie (void); void runSession (void) { sessionDataSet = true; } /*! * Accessors */ //@{ void setUsername (string& user) { nxUsername = user; } void setPassword (string& pass) { nxPassword = pass; } void setResolution (int x, int y) { this->sessionData->xRes = x; this->sessionData->yRes = y; } void setDepth (int d) { this->sessionData->depth = d; } void setRender (bool isRender) { if (this->sessionDataSet) { this->sessionData->render = isRender; } } void setEncryption (bool enc) { if (this->sessionDataSet) { this->sessionData->encryption = enc; } } void setContinue (bool allow) { doSSH = allow; } void setSessionData (NXSessionData*); NXSessionData* getSessionData() { return this->sessionData; } bool getSessionDataSet (void) { return this->sessionDataSet; } void setCallbacks (NXSessionCallbacks * cb) { this->callbacks = cb; } //@} private: void reset (void); void fillRand(unsigned char *, size_t); /*! * This is the answer to give to the ssh server if it * asks whether we want to continue (say, if we're * connecting for the first time and we don't * necessarily trust its SSL key). */ bool doSSH; /*! * Set to true if there are suspended sessions on the * server which are owned by nxUsername. */ bool suspendedSessions; /*! * Set to true of sessionData has been populated */ bool sessionDataSet; /*! * Holds the stage of the process which we have * reached as we go through the process of * authenticating with the NX Server. */ int stage; /*! * File descriptor for the random number device */ int devurand_fd; /*! * Holds the username for this session */ string nxUsername; /*! * Holds the password for this session */ string nxPassword; /*! * A list of sessions which can be resumed, as strings. */ list resumeSessions; /*! * A list of running sessions, held as NXResumeData * structures. */ list runningSessions; /*! * Data for this session. */ NXSessionData *sessionData; /*! * Pointer to a class containing callback methods. */ NXSessionCallbacks * callbacks; }; } // namespace #endif nxcl-0.9/lib/nxclientlib_i18n.h0000644000175000017500000000140510764221506015072 0ustar mjj29mjj29extern "C" { #ifndef __NXCLIENTLIB_I18N__ # define __NXCLIENTLIB_I18N__ #define _(String) (String) #define N_(String) String /* # ifdef HAVE_CONFIG_H # include # endif # ifdef ENABLE_NLS # include "../lib/gettext.h" # define _(String) gettext (String) # define gettext_noop(String) String # define N_(String) gettext_noop (String) # else # define _(String) (String) # define N_(String) String # define textdomain(Domain) (Domain) # define gettext(String) (String) # define dgettext(Domain,String) (String) # define dcgettext(Domain,String,Type) (String) # define bindtextdomain(Domain, Directory) (Domain) # define bind_textdomain_codeset(Domain,Codeset) (Codeset) # endif */ #endif /* __NXCLIENTLIB_I18N__ */ } nxcl-0.9/lib/nxclientlib.h0000644000175000017500000003454710764221506014250 0ustar mjj29mjj29/*************************************************************************** nxclientlib.h ------------------- begin : Sat 22nd July 2006 remove Qt dependency : Started June 2007 modifications : June-July 2007 copyright : (C) 2006 by George Wright modifications : (C) 2007 Embedded Software Foundry Ltd. (U.K.) : Author: Sebastian James : (C) 2008 Defuturo Ltd : Author: George Wright email : seb@esfnet.co.uk, gwright@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #ifndef _NXCLIENTLIB_H_ #define _NXCLIENTLIB_H_ #include #include "nxsession.h" #include #include "notQt.h" using namespace std; namespace nxcl { struct ProxyData { string id; int display; string cookie; string proxyIP; bool encrypted; int port; string server; }; /*! * Callbacks which are to be defined by the client code of * NXClientLib objects. In the case of nxcl, that means the * code in the class Nxcl in nxcl.cpp. */ class NXClientLibExternalCallbacks { public: NXClientLibExternalCallbacks () {} virtual ~NXClientLibExternalCallbacks () {} virtual void write (string msg) {} virtual void write (int num, string msg) {} virtual void error (string msg) {} virtual void debug (string msg) {} virtual void stdoutSignal (string msg) {} virtual void stderrSignal (string msg) {} virtual void stdinSignal (string msg) {} virtual void resumeSessionsSignal (list) {} virtual void noSessionsSignal (void) {} virtual void serverCapacitySignal (void) {} virtual void connectedSuccessfullySignal (void) {} }; /*! * Have to derive NXClientLib from an abstract base class, * NXClientLibBase, so that NXClientLibCallbacks can * hold a pointer to an NXClientLib object. * * The functions that are declared in NXClientLibBase are the * ones that we want to call via this->parent in * NXClientLibCallbacks. They're the ones that are called from * within objects of other classes (such as this->session * (NXSession) or this->nxsshProcess (notQProcess). */ class NXClientLibBase { public: NXClientLibBase() {} virtual ~NXClientLibBase() {} virtual void setIsFinished (bool status) {} virtual void processParseStdout (void) {} virtual void processParseStderr (void) {} virtual void loginFailed (void) {} virtual void readyproxy (void) {} virtual void doneAuth (void) {} /*! * External callbacks pointer is held in NXClientLibBase * because NXClientLibProcessCallbacks::parent is of * type NXClientLibBase and in NXClientLibProcessCallbacks we * refer to this->parent->externalCallbacks->write() */ NXClientLibExternalCallbacks * externalCallbacks; }; /*! * Callbacks class. This derives from several other base * callbacks classes, defining the behaviour of the callbacks. */ class NXClientLibCallbacks : public notQProcessCallbacks, public NXSessionCallbacks { public: NXClientLibCallbacks(); ~NXClientLibCallbacks(); /*! * The callback signals */ //@{ /*! * From notQProcess: */ //@{ void startedSignal (string name); void errorSignal (int error); void processFinishedSignal (string name); void readyReadStandardOutputSignal (void); void readyReadStandardErrorSignal (void); //@} /*! * From NXSession: */ //@{ void noSessionsSignal (void); void loginFailedSignal (void); void readyForProxySignal (void); void authenticatedSignal (void); void sessionsSignal (list); //@} //@} /*! * Accessor function to set a pointer to the parent NXCLientLib * object. */ void setParent (NXClientLibBase * p) { this->parent = p; } private: NXClientLibBase * parent; }; class NXClientLib : public NXClientLibBase { public: NXClientLib(); ~NXClientLib(); /*! * Set up data and then call this->nxsshProcess.start(). * * \param publicKey is the path to the ssh public key * file to authenticate with. Pass "supplied" to use * a new key, which you should then supply as the * parameter key. * * \param serverHost is the hostname of the NX server to * connect to * * \param encryption is whether to use an encrypted NX * session * * \param key ssh key to use for authentication of the * nx user if publicKey is "supplied". * * \param port TCP port to use for the ssh connection. */ void invokeNXSSH (string publicKey = "supplied", string serverHost = "", bool encryption = true, string key = "", int port = 22); /*! * Overloaded to give callback data on write. * * Writes data to this->nxsshProcess stdin and also * out to the user via stdoutCallback */ void write (string data); /*! * Sets a custom binary search path */ void setCustomPath(string path) { this->customPath = path; } /*! * Passes auth to this->session.setContinue() */ void allowSSHConnect (bool auth); /*! * Set up data and then call this->nxproxyProcess.start() */ void invokeProxy (void); /*! * Parse a line of output from * this->nxsshProcess. This is called when the proxy * has started, or if NX authentication * failed. Otherwise, this->session.parseSSH() is * used. */ string parseSSH (string message); /*! * Read through the nx session file, and if we find a * message saying "Session: Terminating session at * 'some date'" we need to set isFinished to true. */ //void checkSession (void); /*! * Re-set the contents of this->session.sessionData * with the nth choice. * * \return true if the nth session is resumable, false * if not, or if there is no nth session. */ bool chooseResumable (int n); /*! * Re-set the contents of this->session.sessionData * with the nth choice such that a terminate session * message will be sent to the nxserver * * \return true if the nth session is terminatable, false * if not, or if there is no nth session. */ bool terminateSession (int n); void runSession (void); void startX11 (string resolution, string name); bool needX11Probe (void) { return x11Probe; } // public slots: //@{ void doneAuth (void); void loginFailed (void); void finished (void) { dbgln ("Finishing up on signal"); this->isFinished = true; } void readyproxy (void) { dbgln ("ready for nxproxy"); this->readyForProxy = true; } void reset (void); void processParseStdout (void); void processParseStderr (void); /*! * SSH requests confirmation to go ahead with * connecting (e.g. if you haven't connected to the * host before) */ void requestConfirmation (string msg); //@} // Accessors //@{ /*! * Set the username for NX to log in with */ void setUsername (string& user) { this->nxuser = user; this->session.setUsername (this->nxuser); } /*! * Set the password for NX to log in with */ void setPassword (string& pass) { this->nxpass = pass; this->session.setPassword (this->nxpass); } void setResolution (int x, int y) { this->session.setResolution(x, y); } void setDepth (int depth) { this->session.setDepth(depth); } void setRender (bool render) { this->session.setRender(render); } void setSessionData (NXSessionData *); notQProcess* getNXSSHProcess (void) { return this->nxsshProcess; } notQProcess* getNXProxyProcess (void) { return this->nxproxyProcess; } notQProcess* getX11Process (void) { return this->x11Process; } notQProcess* getNXAuthProcess (void) { return this->nxauthProcess; } bool getIsFinished (void) { return this->isFinished; } bool getReadyForProxy (void) { return this->readyForProxy; } NXSession* getSession (void) { return &this->session; } void setIsFinished (bool status) { this->isFinished = status; } void setExternalCallbacks (NXClientLibExternalCallbacks * cb) { this->externalCallbacks = cb; } bool getSessionRunning (void) { return this->sessionRunning; } //@} private: /*! * Try a number of different paths to try to find the * program prog's full path. * * \param prog The program to find, likely to be nxssh * or nxproxy. * * \return The full path; e.g. /usr/bin/nxssh */ string getPath (string prog); /*! * Custom search path */ string customPath; bool x11Probe; /*! * Set true when the program is ready to end, e.g if * authentication failed, nxssh failed to start amoung * other reasons. */ bool isFinished; /*! * Set true when nxssh is ready to launch the nxproxy process. */ bool readyForProxy; /*! * Set true when the NX session is under way. This * means we can reduce the polling frequency right * down to a level which won't impact on power * consumption. */ bool sessionRunning; /*! * Have we said we need to enter a password? */ bool password; // FIXME: I hold the actual data, and a pointer to the // data here. I tried to get rid of the pointer, and // modify main.cpp in ../nxcl and that didn't work // properly - I'm not sure why. I suppose I could get // rid of the objects here, and then call // pNxsshProcess = new notQProcess; in the // constructor... /*! * The nxssh process object */ notQProcess* nxsshProcess; /*! * The nxproxy process object */ notQProcess* nxproxyProcess; /*! * The X11 process object */ notQProcess* x11Process; /*! * The nxauth process object */ notQProcess* nxauthProcess; /*! * A callbacks object. This holds the various callback * methods. The callback methods are defined here, but * are callable from notQProcess etc. */ NXClientLibCallbacks callbacks; /*! * A temporary file to hold the ssl key */ notQTemporaryFile *keyFile; /*! * The NX Session object. */ NXSession session; /*! * A structure holding information about the * connection to be made, such as server address, port * and id. */ ProxyData proxyData; /*! * Username for the connection */ string nxuser; /*! * Password for the connection */ string nxpass; }; } // namespace #endif nxcl-0.9/lib/i18n.h0000644000175000017500000000126510764221506012503 0ustar mjj29mjj29#ifndef __NXCL_I18N__ # define __NXCL_I18N__ # ifdef HAVE_CONFIG_H # include # endif # ifdef ENABLE_NLS # include "../lib/gettext.h" # define _(String) gettext (String) # define gettext_noop(String) String # define N_(String) gettext_noop (String) # else # define _(String) (String) # define N_(String) String # define textdomain(Domain) (Domain) # define gettext(String) (String) # define dgettext(Domain,String) (String) # define dcgettext(Domain,String,Type) (String) # define bindtextdomain(Domain, Directory) (Domain) # define bind_textdomain_codeset(Domain,Codeset) (Codeset) # endif /* ENABLE_NLS */ #endif /* __NXCL_I18N__ */ nxcl-0.9/lib/nxdata.h0000644000175000017500000000622510764221506013204 0ustar mjj29mjj29/*************************************************************************** nxdata.h ------------------- begin : Wednesday 9th August 2006 modifications : July 2007 copyright : (C) 2006 by George Wright modifications : (C) 2007 Embedded Software Foundry Ltd. (U.K.) : Author: Sebastian James email : seb@esfnet.co.uk, gwright@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #ifndef _NXDATA_H_ #define _NXDATA_H_ #include /*! * Some definitions of numbers that we can send over to the frontend * client to tell it how we're getting along with the connection... */ #define NXCL_PROCESS_STARTED 1000001 #define NXCL_PROCESS_EXITED 1000002 #define NXCL_AUTH_FAILED 1000003 #define NXCL_AUTHENTICATING 1000004 #define NXCL_LOGIN_FAILED 1000005 #define NXCL_HOST_KEY_VERIFAILED 1000006 #define NXCL_INVOKE_PROXY 1000007 #define NXCL_STARTING 1000008 #define NXCL_FINISHED 1000009 #define NXCL_ALIVE 1000010 #define NXCL_PROCESS_ERROR 1000011 using namespace std; namespace nxcl { struct NXConfigData { string serverHost; int serverPort; string sessionUser; string sessionPass; string sessionName; string sessionType; int cache; int images; string linkType; bool render; string backingstore; int imageCompressionMethod; int imageCompressionLevel; string geometry; string keyboard; string kbtype; bool media; string agentServer; string agentUser; string agentPass; int cups; string key; bool encryption; bool fullscreen; bool virtualDesktop; string customCommand; }; struct NXSessionData { string sessionName; string sessionType; int cache; int images; string linkType; bool render; string backingstore; int imageCompressionMethod; int imageCompressionLevel; string geometry; string keyboard; string kbtype; bool media; string agentServer; string agentUser; string agentPass; int cups; string id; string key; bool encryption; bool fullscreen; bool virtualDesktop; string customCommand; bool suspended; int xRes; int yRes; int depth; int display; bool terminate; }; struct NXResumeData { int display; string sessionType; string sessionID; string options; int depth; string screen; string available; string sessionName; }; } // namespace #endif nxcl-0.9/lib/notQt.cpp0000644000175000017500000003275010764221506013367 0ustar mjj29mjj29/*************************************************************************** notQt.cpp: A set of Qt like functionality, especially related to the starting of processes. ------------------- begin : June 2007 copyright : (C) 2007 Embedded Software Foundry Ltd. (U.K.) : Author: Sebastian James email : seb@esfnet.co.uk ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #include #include extern "C" { #include #include #include #include #include #include #include } #include "../config.h" #include "notQt.h" using namespace std; using namespace nxcl; /*! * Implementation of the notQProcess class */ //@{ // Used when dealing with pipes #define READING_END 0 #define WRITING_END 1 #define STDIN 0 #define STDOUT 1 #define STDERR 2 // Constructor notQProcess::notQProcess () : progName("unknown"), error (NOTQPROCNOERROR), pid(0), signalledStart(false) { // Set up the polling structs this->p = static_cast(malloc (2*sizeof (struct pollfd))); } // Destructor notQProcess::~notQProcess () { free (this->p); } void notQProcess::writeIn (string& input) { write (this->parentToChild[WRITING_END], input.c_str(), input.size()); } // fork and exec a new process using execv, which takes stdin via a // fifo and returns output also via a fifo. int notQProcess::start (const string& program, const list& args) { char** argarray; list myargs = args; list::iterator i; unsigned int j = 0; int theError; // NB: The first item in the args list should be the program name. this->progName = program; // Set up our pipes if (pipe(parentToChild) == -1 || pipe(childToParent) == -1 || pipe(childErrToParent) == -1) { return NOTQTPROCESS_FAILURE; } this->pid = fork(); switch (this->pid) { case -1: return NOTQTPROCESS_FAILURE; case 0: // This is the CHILD process // Close unwanted ends of the pipes close (parentToChild[WRITING_END]); close (childToParent[READING_END]); close (childErrToParent[READING_END]); // Now all we have to do is make the writing file // descriptors 0,1 or 2 and they will be used instead // of stdout, stderr and stdin. if ((dup2 (parentToChild[READING_END], STDIN)) == -1 || (dup2 (childToParent[WRITING_END], STDOUT)) == -1 || (dup2 (childErrToParent[WRITING_END], STDERR)) == -1) { theError = errno; cout << "ERROR! Couldn't get access to stdin/out/err! errno was " << theError << endl; return NOTQTPROCESS_FAILURE; } // Allocate memory for the program arguments // 1+ to allow space for NULL terminating pointer argarray = static_cast(malloc ((1+args.size()) * sizeof (char*))); for (i=myargs.begin(); i!=myargs.end(); i++) { argarray[j] = static_cast(malloc ( (1+(*i).size()) * sizeof (char) )); snprintf (argarray[j++], 1+(*i).size(), "%s", (*i).c_str()); dbgln(*i); } argarray[j] = NULL; dbgln ("About to execute '" + program + "' with those arguments.."); execv (program.c_str(), argarray); // If process returns, error occurred theError = errno; // This'll get picked up by parseResponse cout << "notQProcess error: " << this->pid << " crashed. errno:" << theError << endl; // This won't get picked up by the parent process. this->error = NOTQPROCCRASHED; // In this case, we close the pipes to signal to the parent that we crashed close (parentToChild[READING_END]); close (childToParent[WRITING_END]); close (childErrToParent[WRITING_END]); // Child should exit now. _exit(-1); default: // This is the PARENT process // Close unwanted ends of the pipes close (parentToChild[READING_END]); close (childToParent[WRITING_END]); close (childErrToParent[WRITING_END]); // Write to this->parentToChild[WRITING_END] to write to stdin of the child // Read from this->childToParent[READING_END] to read from stdout of child // Read from this->childErrToParent[READING_END] to read from stderr of child break; } return NOTQTPROCESS_MAIN_APP; } // If no pid after a while, return false. bool notQProcess::waitForStarted (void) { unsigned int i=0; while (this->pid == 0 && i<1000) { usleep (1000); i++; } if (this->pid>0) { dbgln ("The process started!"); this->callbacks->startedSignal (this->progName); this->signalledStart = true; return true; } else { this->error = NOTQPROCFAILEDTOSTART; this->callbacks->errorSignal (this->error); return false; } } // Send a TERM signal to the process. void notQProcess::terminate (void) { kill (this->pid, 15); // 15 is TERM // Now check if the process has gone and kill it with signal 9 (KILL) this->pid = 0; this->error = NOTQPROCNOERROR; this->signalledStart = false; return; } // Check on this process void notQProcess::probeProcess (void) { // Has the process started? if (!this->signalledStart) { if (this->pid > 0) { this->callbacks->startedSignal (this->progName); this->signalledStart = true; dbgln ("notQProcess::probeProcess set signalledStart and signalled the start..."); } } // Check for error condition if (this->error>0) { this->callbacks->errorSignal (this->error); dbgln ("have error in probeProcess, returning"); return; } if (this->pid == 0) { // Not yet started. return; } // Why can't these 4 lines go in contructor? this->p[0].fd = this->childToParent[READING_END]; this->p[0].events = POLLIN | POLLPRI; this->p[1].fd = this->childErrToParent[READING_END]; this->p[1].events = POLLIN | POLLPRI; // Poll to determine if data is available this->p[0].revents = 0; this->p[1].revents = 0; poll (this->p, 2, 0); if (this->p[0].revents & POLLNVAL || this->p[1].revents & POLLNVAL) { dbgln ("notQProcess::probeProcess: pipes closed, process must have crashed"); this->error = NOTQPROCCRASHED; this->callbacks->errorSignal (this->error); return; } if (this->p[0].revents & POLLIN || this->p[0].revents & POLLPRI) { this->callbacks->readyReadStandardOutputSignal(); } if (this->p[1].revents & POLLIN || this->p[1].revents & POLLPRI) { this->callbacks->readyReadStandardErrorSignal(); } // Is the process running? We check last, so that we get any // messages on stdout/stderr that we may wish to process, such // as error messages from nxssh key authentication. int theError; if (this->signalledStart == true) { int rtn = 0; if ((rtn = waitpid (this->pid, (int *)0, WNOHANG)) == this->pid) { this->callbacks->processFinishedSignal (this->progName); return; } else if (rtn == -1) { theError = errno; if (theError != 10) { // We ignore errno 10 "no child" as this commonly occurs cerr << "waitpid returned errno: " << theError; } } // else rtn == 0 } return; } // Read stdout pipe, without blocking. string notQProcess::readAllStandardOutput (void) { string s; int bytes = 0; char c; struct pollfd p; p.fd = this->childToParent[READING_END]; p.events = POLLIN | POLLPRI; // We know we have at least one character to read, so seed revents p.revents = POLLIN; while (p.revents & POLLIN || p.revents & POLLPRI) { // This read of 1 byte should never block if ((bytes = read (this->childToParent[READING_END], &c, 1)) == 1) { s.append (1, c); } p.revents = 0; poll (&p, 1, 0); } return s; } // Read stderr pipe without blocking string notQProcess::readAllStandardError (void) { string s; int bytes = 0; char c; struct pollfd p; p.fd = this->childErrToParent[READING_END]; p.events = POLLIN | POLLPRI; // We know we have at least one character to read, so seed revents p.revents = POLLIN; while (p.revents & POLLIN || p.revents & POLLPRI) { // This read of 1 byte should never block because a poll() call tells us there is data if ((bytes = read (this->childErrToParent[READING_END], &c, 1)) == 1) { s.append (1, c); } p.revents = 0; poll (&p, 1, 0); } return s; } //@} /*! * Implementation of the notQTemporaryFile class */ //@{ // Constructor notQTemporaryFile::notQTemporaryFile () { } // Destructor notQTemporaryFile::~notQTemporaryFile () { this->close(); } void notQTemporaryFile::open (void) { stringstream fn; fn << "/tmp/notQt" << time(NULL); this->theFileName = fn.str(); this->f.open (this->theFileName.c_str(), ios::in|ios::out|ios::trunc); } void notQTemporaryFile::write (string input) { this->f << input; } void notQTemporaryFile::close (void) { if (this->f.is_open()) { this->f.close(); } } // getter for fileName string notQTemporaryFile::fileName (void) { return this->theFileName; } void notQTemporaryFile::remove (void) { this->close(); unlink (this->theFileName.c_str()); } //@} /*! * Implementation of the notQtUtilities class */ //@{ // Constructor notQtUtilities::notQtUtilities () { } // Destructor notQtUtilities::~notQtUtilities () { } string notQtUtilities::simplify (string& input) { string workingString; unsigned int i=0, start, end; // Find the first non-whitespace character. while (input[i] != '\0' && (input[i] == ' ' || input[i] == '\t' || input[i] == '\n' || input[i] == '\r') && i0) { i--; } end = ++i; // Copy the substring into a working string. if (end>start) { workingString = input.substr (start, end-start); } else { return ""; } // Now we replace internal white spaces in workingString with single spaces. for (i=workingString.size(); i>1; --i) { if ( (workingString[i] == ' ' || workingString[i] == '\t' || workingString[i] == '\n' || workingString[i] == '\r') && (workingString[i-1] == ' ' || workingString[i-1] == '\t' || workingString[i-1] == '\n' || workingString[i-1] == '\r') ) { // ...then this is a whitespace we can remove workingString.erase(i,1); } else if ( (workingString[i] == '\t' || workingString[i] == '\n' || workingString[i] == '\r') && (workingString[i-1] != ' ' && workingString[i-1] != '\t' && workingString[i-1] != '\n' && workingString[i-1] != '\r') ) { // ...then this is a non-space whitespace to be replaced workingString.replace(i, 1, " "); } } return workingString; } // split based on token ' ' void notQtUtilities::splitString (string& line, char token, vector& rtn) { rtn.clear(); unsigned int i=0; while (i < (line.size())-1) { string tstring; while (line[i] && line[i] != token) { tstring.push_back(line[i++]); } rtn.push_back(tstring); i++; } return; } void notQtUtilities::splitString (string& line, char token, list& rtn) { rtn.clear(); unsigned int i=0; while (i < (line.size())-1) { string tstring; while (line[i] && line[i] != token) { //dbgln ("tstring.push_back line[i] which is '" << line[i] << "'"); tstring.push_back(line[i++]); } //dbgln ("rtn.push_back() tstring which is '" + tstring + "'"); rtn.push_back(tstring); i++; } return; } int notQtUtilities::ensureUnixNewlines (std::string& input) { int num = 0; for (unsigned int i=0; i #include "notQt.h" #include "nxclientlib.h" #include "nxsession.h" using namespace std; using namespace nxcl; NXSession::NXSession() : devurand_fd(-1), stage(HELLO_NXCLIENT), sessionDataSet(false), nxUsername("nouser"), nxPassword("nopass") { } NXSession::~NXSession() { } void NXSession::resetSession() { this->stage = 0; this->sessionDataSet = false; } string NXSession::parseSSH(string message) { dbgln ("NXSession::parseSSH called for: " + message); int response = parseResponse (message); string returnMessage; if (response == 211) { if (doSSH == true) { returnMessage = "yes"; doSSH = false; } else returnMessage = "no"; } if (response == 204) { // Authentication failed returnMessage = "204"; } if (response == 147) { // Server capacity reached returnMessage = "147"; this->stage = FINISHED; } switch (this->stage) { case HELLO_NXCLIENT: dbgln ("HELLO_NXCLIENT stage"); if (message.find("HELLO NXSERVER - Version") != string::npos) { this->callbacks->authenticatedSignal(); returnMessage = "hello NXCLIENT - Version "; returnMessage.append(CLIENT_VERSION); this->stage++; } break; case ACKNOWLEDGE: dbgln ("ACKNOWLEDGE stage"); if (response == 105) this->stage++; break; case SHELL_MODE: dbgln ("SHELL_MODE stage"); if (response == 105) { returnMessage = "SET SHELL_MODE SHELL"; this->stage++; } break; case AUTH_MODE: dbgln ("AUTH_MODE stage"); if (response == 105) { returnMessage = "SET AUTH_MODE PASSWORD"; this->stage++; } break; case LOGIN: dbgln ("LOGIN stage"); switch (response) { case 105: returnMessage = "login"; break; case 101: returnMessage = nxUsername; break; case 102: returnMessage = nxPassword; break; case 103: this->stage++; break; case 404: this->callbacks->loginFailedSignal(); } break; case LIST_SESSIONS: dbgln ("LIST_SESSIONS stage"); if (this->sessionData->terminate == true) { // Wait for termination dbgln ("Waiting for termination"); if (response == 900) { stringstream termsession; termsession << "NX> 900 Session id: " << this->sessionData->id << " terminated."; if (message.find (termsession.str().c_str(), 0) == 0) { // Session terminated. this->sessionData->terminate = false; } else { usleep (10000); } } } else if (response == 105) { // Get a list of the available sessions on the server, for // given user, with given status, and any type. Not sure if // geometry is ignored or not. stringstream ss; // We want to list suspended or running sessions, with this // command: dbgln ("this->resumeSessions.size() == " << this->resumeSessions.size()); if (this->sessionData->sessionType == "shadow") { // This is how to list shadow sessions. Run NoMachine's // client and see ~/.nx/temp/(pid)/sshlog for connection // details ss << "listsession --type=\"shadow\""; } else { ss << "listsession --user=\"" << nxUsername << "\" --status=\"suspended,running\" --geometry=\"" << this->sessionData->xRes << "x" << this->sessionData->yRes << "x" << this->sessionData->depth << (this->sessionData->render ? "+render" : "") // If you leave --type blank, you can re-connect to any // sessions available. << "\" --type=\"" << this->sessionData->sessionType << "\""; } returnMessage = ss.str(); this->stage++; } break; case PARSESESSIONS: dbgln ("PARSESESSIONS stage"); if ((this->sessionData->sessionType == "shadow" && response != 105) || (this->sessionData->sessionType != "shadow" && response != 148) ) { dbgln ("Building resumeSessions:" << " resumeSessions.push_back(message);"); this->resumeSessions.push_back(message); } else if ((this->sessionData->sessionType == "shadow" && response == 105) || (this->sessionData->sessionType != "shadow" && response == 148)) { dbgln ("Parsing resumeSessions:" << " parseResumeSessions(resumeSessions);"); parseResumeSessions (this->resumeSessions); dbgln ("parseResumeSessions(resumeSessions) returned"); // Now, the problem we have here, is that when // we return from the last 105 response, we // don't then get another stdout message to // act upon. So, we want to recurse back into // parseSSH to get onto the STARTSESSION stage here: returnMessage = this->parseSSH (message); } break; case STARTSESSION: dbgln ("STARTSESSION stage"); if (response == 105 && sessionDataSet) { dbgln ("response is 105 and sessionDataSet is true");; int media = 0; string fullscreen = ""; if (this->sessionData->media) { media = 1; } if (this->sessionData->fullscreen) { this->sessionData->geometry = "fullscreen"; fullscreen = "+fullscreen"; } if (this->sessionData->sessionType == "shadow" && this->sessionData->terminate == false) { dbgln ("It's a shadow session!"); stringstream ss; // These are the session parameters that NoMachine's client // sends for resume ss << "attachsession " << "--link=\"" << this->sessionData->linkType << "\" " << "--backingstore=\"" << this->sessionData->backingstore << "\" " << "--encryption=\"" << this->sessionData->encryption << "\" " << "--cache=\"" << this->sessionData->cache << "M\" " << "--images=\"" << this->sessionData->images << "M\" " // probably has been autodetected from my display << "--shmem=\"1\" " // probably has been autodetected from my display << "--shpix=\"1\" " // probably has been autodetected from my display << "--strict=\"0\" " // probably has been autodetected from my display << "--composite=\"1\" " << "--media=\"" << media << "\" " << "--session=\"" << this->sessionData->sessionName << "\" " << "--type=\"" << this->sessionData->sessionType << "\" " // FIXME: This may be some other OS if you compile it on // Sun, Windows, etc. << "--client=\"linux\" " << "--keyboard=\"" << this->sessionData->keyboard << "\" " << "--id=\"" << this->sessionData->id << "\" " // This may be the key? << "--display=\"0\" " << "--geometry=\"" << this->sessionData->geometry << "\" "; returnMessage = ss.str(); dbgln ("session parameter command: " + ss.str()); this->stage++; } else if (this->sessionData->terminate == true) { stringstream ss; // These are the session parameters that NoMachine's client // sends for resume ss << "Terminate --sessionid=\"" << this->sessionData->id << "\""; returnMessage = ss.str(); dbgln ("session parameter command: " + ss.str()); // Back to listsessions after terminating a session. this->stage -= 2; // Clear the list of sessions to resume this->resumeSessions.clear(); this->runningSessions.clear(); } else if (this->sessionData->suspended) { dbgln ("this->sessionData->suspended is true"); stringstream ss; // These are the session parameters that NoMachine's client // sends for resume ss << "restoresession --id=\"" << this->sessionData->id << "\" --session=\"" << this->sessionData->sessionName << "\" --type=\"" << this->sessionData->sessionType << "\" --cache=\"" << this->sessionData->cache << "M\" --images=\"" << this->sessionData->images << "M\" --cookie=\"" << generateCookie() << "\" --link=\"" << this->sessionData->linkType << "\" --kbtype=\"" << this->sessionData->kbtype << "\" --nodelay=\"1\" --encryption=\"" << this->sessionData->encryption << "\" --backingstore=\"" << this->sessionData->backingstore << "\" --geometry=\"" << this->sessionData->geometry << "\" --media=\"" << media << "\" --agent_server=\"" << this->sessionData->agentServer << "\" --agent_user=\"" << this->sessionData->agentUser << "\" --agent_password=\"" << this->sessionData->agentPass << "\""; returnMessage = ss.str(); dbgln ("session parameter command: " + ss.str()); this->stage++; } else { dbgln ("this->sessionData->suspended is false, and it's" << " not a shadow session."); stringstream ss; ss << "startsession --session=\"" << this->sessionData->sessionName << "\" --type=\"" << this->sessionData->sessionType << "\" --cache=\"" << this->sessionData->cache << "M\" --images=\"" << this->sessionData->images << "M\" --cookie=\"" << generateCookie() << "\" --link=\"" << this->sessionData->linkType << "\" --render=\"" << (this->sessionData->render ? 1 : 0) << "\" --encryption=\"" << this->sessionData->encryption << "\" --backingstore=\"" << this->sessionData->backingstore << "\" --imagecompressionmethod=\"" << this->sessionData->imageCompressionMethod << "\" --geometry=\"" << this->sessionData->geometry << "\" --screeninfo=\"" << this->sessionData->xRes << "x" << this->sessionData->yRes << "x" << this->sessionData->depth << (this->sessionData->render ? "+render" : "") << fullscreen << "\" --keyboard=\"" << this->sessionData->keyboard << "\" --kbtype=\"" << this->sessionData->kbtype << "\" --media=\"" << media << "\" --agent_server=\"" << this->sessionData->agentServer << "\" --agent_user=\"" << this->sessionData->agentUser << "\" --agent_password=\"" << this->sessionData->agentPass << "\""; ss << " --title=\"sebtest\""; // testing a window title if (this->sessionData->sessionType == "unix-application") { ss << " --application=\"" << this->sessionData->customCommand << "\""; if (this->sessionData->virtualDesktop == true) { ss << " --rootless=\"0\" --virtualdesktop=\"1\""; } else { ss << " --rootless=\"1\" --virtualdesktop=\"0\""; } } else if (this->sessionData->sessionType == "unix-console") { if (this->sessionData->virtualDesktop == true) { ss << " --rootless=\"0\" --virtualdesktop=\"1\""; } else { ss << " --rootless=\"1\" --virtualdesktop=\"0\""; } } else if (this->sessionData->sessionType == "unix-default") { // ignore this - does anyone use it? } returnMessage = ss.str(); dbgln ("session parameter command: " + ss.str()); this->stage++; } } else { dbgln ("either response is not 105 or sessionDataSet is" << " false."); } break; case FINISHED: dbgln ("FINISHED stage. Response is " << response << ". That should mean that session set up is complete."); this->callbacks->readyForProxySignal(); } dbgln ("NXSession::parseSSH, about to return a message: " + returnMessage); if (!returnMessage.empty()) { returnMessage.append("\n"); return returnMessage; } else return ""; } void NXSession::setSessionData (NXSessionData *sd) { this->sessionData = sd; } int NXSession::parseResponse(string message) { string::size_type idx1, idx2; int response; dbgln ("NXSession::parseResponse called for message:" << message); if ((idx1 = message.find ("notQProcess error", 0)) != string::npos) { dbgln ("Found notQProcess error"); // This means a process crashed, we're going to return a number >100000 // to indicate this. if ( ((idx2 = message.find ("crashed", 0)) != string::npos) && idx2 > idx1) { stringstream ss; ss << message.substr((idx1+19), idx2-1-(idx1+19)); // This is the pid that crashed ss >> response; // Add 100000 and return this response += 100000; return response; } else { dbgln ("Uh oh, didn't find \"crashed\""); } } // Find out the server response number // This will only be present in strings which contain "NX>" if (message.find("NX>") != string::npos && message.find("NX>") == 0) { idx1 = message.find("NX>") + 4; if ((idx2 = message.find(" ", idx1)) == string::npos) { if ((idx2 = message.find("\n", idx1)) == string::npos) { idx2 = message.size(); } } if (idx2>idx1) { stringstream ss; ss << message.substr(idx1, idx2-idx1); ss >> response; } else { response = 0; } } else { response = 0; } dbgln ("NXSession::parseResponse() returning " << response); return response; } void NXSession::parseResumeSessions(list rawdata) { // Was: QStringList sessions, and got rawdata appended to it? list sessions; list::iterator iter, at; dbgln ("NXSession::parseResumeSessions called."); for (iter = rawdata.begin(); iter != rawdata.end(); iter++) { if (((*iter).find("-------") != string::npos) && !(*iter).empty()) { at = iter; } } for (iter = ++at; iter != rawdata.end(); iter++) { if ((!(*iter).find("NX> 148") != string::npos) && !(*iter).empty()) { sessions.push_back(*iter); } } list < vector > rawsessions; list < vector >::iterator rsIter; // Clean up each string in sessions[i], then push back // sessions[i] onto rawsessions., except that means // rawsessions is then just a list... vector session; vector::iterator seshIter; for (iter = sessions.begin(); iter != sessions.end(); iter++) { session.clear(); // Simplify one line of list sessions (*iter) = notQtUtilities::simplify (*iter); // Split one line of list sessions into a vector notQtUtilities::splitString (*iter, ' ', session); // Add that to rawsessions rawsessions.push_back(session); } NXResumeData resData; for (rsIter = rawsessions.begin(); rsIter != rawsessions.end(); rsIter++) { stringstream ss1, ss2; int tmp; dbgln ("*rsIter.size() == " << (*rsIter).size()); ss1 << (*rsIter)[0]; ss1 >> tmp; resData.display = tmp; dbgln ("resData.display = " << resData.display); resData.sessionType = (*rsIter)[1]; dbgln ("resData.sessionType = " << resData.sessionType); resData.sessionID = (*rsIter)[2]; dbgln ("resData.sessionID = " << resData.sessionID); resData.options = (*rsIter)[3]; dbgln ("resData.options = " << resData.options); ss2 << (*rsIter)[4]; ss2 >> tmp; resData.depth = tmp; dbgln ("resData.depth = " << resData.depth); resData.screen = (*rsIter)[5]; dbgln ("resData.screen = " << resData.screen); resData.available = (*rsIter)[6]; dbgln ("resData.available = " << resData.available); resData.sessionName = (*rsIter)[7]; dbgln ("resData.sessionName = " << resData.sessionName); this->runningSessions.push_back(resData); } if (this->runningSessions.size() != 0) { this->suspendedSessions = true; dbgln ("NXSession::parseResumeSessions(): Calling sessionsSignal."); // runningSessions is a list of NXResumeData this->callbacks->sessionsSignal (this->runningSessions); } else { dbgln ("NXSession::parseResumeSessions(): Calling" << " this->callbacks->noSessionsSignal()"); // In case we previously had one resumable session, // which the user terminated, then we listsessions and // got no resumable sessions, we need to make sure // startsession is called, not restoresession. hence // set sessionData->suspended to false. this->sessionData->suspended = false; this->callbacks->noSessionsSignal(); } dbgln ("Increment stage"); this->stage++; dbgln ("NXSession::parseResumeSessions() returning."); } void NXSession::wipeSessions() { while (!this->runningSessions.empty()) { this->runningSessions.pop_front(); } } string NXSession::generateCookie() { unsigned long long int int1, int2; stringstream cookie; devurand_fd = open("/dev/urandom", O_RDONLY); fillRand((unsigned char*)&int1, sizeof(int1)); fillRand((unsigned char*)&int2, sizeof(int2)); cookie << int1 << int2; return cookie.str(); } void NXSession::fillRand(unsigned char *buf, size_t nbytes) { ssize_t r; unsigned char *where = buf; while (nbytes) { while ((r = read(devurand_fd, where, nbytes)) == -1) where += r; nbytes -= r; } } bool NXSession::chooseResumable (int n) { dbgln ("NXSession::chooseResumable called."); if (this->runningSessions.size() <= static_cast(n)) { // No nth session to resume. dbgln ("No nth session to resume, return false."); return false; } // Set to false while we change contents of sessionData this->sessionDataSet = false; list::iterator it = this->runningSessions.begin(); for (int i = 0; isessionData->sessionType != "shadow") { this->sessionData->sessionType = (*it).sessionType; } this->sessionData->display = (*it).display; this->sessionData->sessionName = (*it).sessionName; this->sessionData->id = (*it).sessionID; stringstream geom; // Plus render, if necessary geom << (*it).screen << "x" << (*it).display; // FIXME: This not yet quite complete. // With depth in there too? this->sessionData->geometry = geom.str(); this->sessionData->suspended=true; this->sessionDataSet = true; dbgln ("NXSession::chooseResumable returning true."); return true; } bool NXSession::terminateSession (int n) { dbgln ("NXSession::terminateSession called."); if (this->runningSessions.size() <= static_cast(n)) { // No nth session to terminate dbgln ("No nth session to terminate, return false."); return false; } // Set to false while we change the contents of sessionData this->sessionDataSet = false; list::iterator it = this->runningSessions.begin(); for (int i = 0; isessionData->terminate = true; this->sessionData->display = (*it).display; this->sessionData->sessionName = (*it).sessionName; this->sessionData->id = (*it).sessionID; this->sessionData->suspended=true; this->sessionDataSet = true; return true; } nxcl-0.9/lib/notQt.h0000644000175000017500000001450210764221506013027 0ustar mjj29mjj29/* -*-c++-*- */ /*************************************************************************** notQt.h: A set of Qt like functionality, especially related to the starting of processes. ------------------- begin : June 2007 copyright : (C) 2007 Embedded Software Foundry Ltd. (U.K.) : Author: Sebastian James email : seb@esfnet.co.uk ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ /*! * \file notQt.h Simple re-implementations of some Qt-like * functionality. In particular, there's a QProcess-like (though much * simplified) class, a QTemporaryFile like class and a couple of the * methods that you get with QString. */ #ifndef _NOTQT_H_ #define _NOTQT_H_ #include #include #include #include extern "C" { #include } #define NOTQTPROCESS_MAIN_APP 0 #define NOTQTPROCESS_FAILURE -1 // Possible errors to be generated #define NOTQPROCNOERROR 0 #define NOTQPROCFAILEDTOSTART 1 #define NOTQPROCCRASHED 2 #define NOTQPROCTIMEDOUT 3 #define NOTQPROCWRITEERR 4 #define NOTQPROCREADERR 5 #define NOTQPROCUNKNOWN 6 using namespace std; #ifdef DEBUG extern ofstream debugLogFile; # define dbgln(msg) debugLogFile << __FUNCTION__ << ": " << msg << endl; # define dbglln(msg) debugLogFile << __PRETTY_FUNCTION__ << ": " << msg << endl; # define dbg(msg) debugLogFile << msg; #else # define dbgln(msg) # define dbglln(msg) # define dbg(msg) #endif namespace nxcl { /*! * A set of virtual callbacks. These should be derived in the * client code. They're called by notQProcess via the * notQProcessCallbacks* callbacks member variable. */ class notQProcessCallbacks { public: notQProcessCallbacks() {} virtual ~notQProcessCallbacks() {} virtual void startedSignal (string) {} virtual void errorSignal (int) {} virtual void processFinishedSignal (string) {} virtual void readyReadStandardOutputSignal (void) {} virtual void readyReadStandardErrorSignal (void) {} }; /*! * notQProcess is a simple replacement for the Qt class QProcess. */ class notQProcess { public: notQProcess(); ~notQProcess(); /*! * Write \arg input to the stdin of the process. */ void writeIn (string& input); /*! * fork and exec the process. */ int start (const string& program, const list& args); /*! * Send a TERM signal to the process. */ void terminate (void); /*! * poll to see if there is data on stderr or stdout * and to see if the process has exited. * * This must be called on a scheduled basis. It checks * for any stdout/stderr data and also checks whether * the process is still running. */ void probeProcess (void); /*! * Accessors */ //@{ pid_t getPid (void) { return this->pid; } int getError (void) { return this->error; } void setError (int e) { this->error = e; } /*! * Setter for the callbacks. */ void setCallbacks (notQProcessCallbacks * cb) { this->callbacks = cb; } //@} /*! * Slots */ //@{ string readAllStandardOutput (void); string readAllStandardError (void); /*! * Wait for the process to get itself going. Do this * by looking at pid. If no pid after a while, * return false. */ bool waitForStarted (void); //@} private: /*! * The name of the program to execute */ string progName; /*! * The environment and arguments of the program to execute */ list environment; /*! * Holds a notQProcess error, defined above. NOTQPROCNOERROR, etc. */ int error; /*! * Process ID of the program */ pid_t pid; /*! * Set to true if the fact that the program has been * started has been signalled using the callback * callbacks->startedSignal */ bool signalledStart; /*! * stdin parent to child */ int parentToChild[2]; /*! * stdout child to parent */ int childToParent[2]; /*! * stderr child to parent */ int childErrToParent[2]; /*! * Used in the poll() call in probeProcess() */ struct pollfd * p; /*! * Pointer to a callback object */ notQProcessCallbacks * callbacks; }; /*! * A simple replacement for the Qt Class QTemporaryFile. */ class notQTemporaryFile { public: notQTemporaryFile(); ~notQTemporaryFile(); /*! * Open a file with a (not really) random name. The * filename will be /tmp/notQtXXXXXX where XXXXXX will * be the time in seconds since the unix epoch. */ void open (void); /*! * Write \arg input to the temporary file. */ void write (string input); /*! * Close the temporary file's stream. */ void close (void); /*! * A getter for the file name of the temporary file */ string fileName (void); /*! * Remove the temporary file */ void remove (void); private: /*! * The file name of the temporary file */ string theFileName; /*! * The file stream for the temporary file */ fstream f; }; /*! * A few useful utility functions. */ class notQtUtilities { public: notQtUtilities(); ~notQtUtilities(); /*! The same (more or less) as Qt QString::simplified */ static string simplify (string& input); /*! * Split a string 'line' based on token, placing the portions in the vector rtn */ static void splitString (string& line, char token, vector& rtn); /*! * Split a string 'line' based on token, placing the portions in the list rtn */ static void splitString (string& line, char token, list& rtn); /*! * Run through input and replace any DOS newlines with unix newlines. */ static int ensureUnixNewlines (std::string& input); }; } // namespace #endif nxcl-0.9/lib/nxclientlib.cpp0000644000175000017500000006507210764221506014600 0ustar mjj29mjj29/*************************************************************************** nxclientlib.cpp ------------------- begin : Sat 22nd July 2006 modifications : July 2007 copyright : (C) 2006 by George Wright modifications : (C) 2007 Embedded Software Foundry Ltd. (U.K.) : Author: Sebastian James : (C) 2008 Defuturo Ltd : Author: George Wright email : seb@esfnet.co.uk, gwright@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #include "nxclientlib_i18n.h" #include "nxclientlib.h" #include "nxdata.h" #include "../config.h" #include extern "C" { #include #include #include #include } /* * On the location of nxproxy and nxssh binaries * --------------------------------------------- * We expect them to be installed in PACKAGE_BIN_DIR (See * Makefile.am). So, if nxcl is installed in /usr/bin/nxcl then we * call /usr/bin/nxssh and /usr/bin/nxproxy, etc etc. */ using namespace std; using namespace nxcl; /*! * Implementation of the NXClientLibCallbacks class */ //@{ NXClientLibCallbacks::NXClientLibCallbacks() { } NXClientLibCallbacks::~NXClientLibCallbacks() { } void NXClientLibCallbacks::startedSignal (string name) { this->parent->externalCallbacks->write (NXCL_PROCESS_STARTED, name + _(" process started")); } void NXClientLibCallbacks::processFinishedSignal (string name) { this->parent->externalCallbacks->write (NXCL_PROCESS_EXITED, name + _(" process exited")); parent->setIsFinished (true); } void NXClientLibCallbacks::errorSignal (int error) { string message; switch (error) { case NOTQPROCFAILEDTOSTART: message = _("The process failed to start"); break; case NOTQPROCCRASHED: message = _("The process has crashed"); break; case NOTQPROCTIMEDOUT: message = _("The process timed out"); break; case NOTQPROCWRITEERR: message = _("There was an error writing to the process"); break; case NOTQPROCREADERR: message = _("There was an error reading from the process"); break; default: message = _("There was an unknown error with the process"); break; } this->parent->externalCallbacks->error (message); } void NXClientLibCallbacks::readyReadStandardOutputSignal() { this->parent->processParseStdout(); } void NXClientLibCallbacks::readyReadStandardErrorSignal() { this->parent->processParseStderr(); } /*! * This gets called from within the NXSession object... */ void NXClientLibCallbacks::noSessionsSignal() { this->parent->externalCallbacks->noSessionsSignal(); } void NXClientLibCallbacks::loginFailedSignal() { this->parent->loginFailed(); } void NXClientLibCallbacks::readyForProxySignal() { this->parent->readyproxy(); } void NXClientLibCallbacks::authenticatedSignal() { this->parent->doneAuth(); } void NXClientLibCallbacks::sessionsSignal (list data) { this->parent->externalCallbacks->resumeSessionsSignal (data); } //@} /*!e * Implementation of the NXClientLib class */ //@{ NXClientLib::NXClientLib() : nxsshProcess(new notQProcess()), nxproxyProcess(new notQProcess()), x11Process(new notQProcess()), nxauthProcess(new notQProcess()) { this->isFinished = false; this->readyForProxy = false; this->sessionRunning = false; this->proxyData.encrypted = false; this->password = false; dbgln ("In NXClientLib constructor"); /* Set up callback pointers */ this->nxsshProcess->setCallbacks (&callbacks); this->nxproxyProcess->setCallbacks (&callbacks); this->x11Process->setCallbacks (&callbacks); this->nxauthProcess->setCallbacks (&callbacks); this->session.setCallbacks (&callbacks); this->callbacks.setParent (this); dbgln ("Returning from NXClientLib constructor"); } NXClientLib::~NXClientLib() { dbgln ("In NXClientLib destructor"); } void NXClientLib::invokeNXSSH (string publicKey, string serverHost, bool encryption, string key, int port) { list arguments; stringstream argtmp; proxyData.server = serverHost; dbgln("invokeNXSSH called"); // We use same environment for the process as was used for the // parent, so remove nxsshProcess->setEnvironment(); // Start to build the arguments for the nxssh command. // notQProcess requires that argv[0] contains the program name arguments.push_back ("nxssh"); argtmp << "-nx"; arguments.push_back (argtmp.str()); argtmp.str(""); argtmp << "-p" << port; arguments.push_back (argtmp.str()); if (publicKey == "supplied") { this->keyFile = new notQTemporaryFile; this->keyFile->open(); argtmp.str(""); argtmp << "-i" << this->keyFile->fileName(); arguments.push_back (argtmp.str()); this->keyFile->write (key); this->keyFile->close(); } else { this->keyFile = NULL; argtmp.str(""); argtmp << "-i" << publicKey; arguments.push_back (argtmp.str()); } argtmp.str(""); argtmp << "nx@" << serverHost; arguments.push_back (argtmp.str()); // These options copied from the way Nomachine's client // specifies the nxssh command - they make good sense. arguments.push_back ("-x"); arguments.push_back ("-2"); arguments.push_back ("-oRhostsAuthentication no"); arguments.push_back ("-oPasswordAuthentication no"); arguments.push_back ("-oRSAAuthentication no"); arguments.push_back ("-oRhostsRSAAuthentication no"); arguments.push_back ("-oPubkeyAuthentication yes"); if (encryption == true) { arguments.push_back("-B"); session.setEncryption (true); } else { session.setEncryption (false); } // -E appears in the call to nxssh for Nomachine's nxclient // -version 3 but not 1.5. Is it there in 2? // nxssh -E gives this message when called: // NX> 285 Enabling skip of SSH config files // ...so there you have the meaning. arguments.push_back ("-E"); // Find a path for the nxssh process using getPath() string nxsshPath = this->getPath ("nxssh"); this->nxsshProcess->start(nxsshPath, arguments); if (this->nxsshProcess->waitForStarted() == false) { this->externalCallbacks->write (NXCL_PROCESS_ERROR, _("Error starting nxssh!")); this->isFinished = true; } } void NXClientLib::requestConfirmation (string msg) { this->externalCallbacks->stdoutSignal (_("This is a placeholder method to deal with sending " "back a yes or a no answer. " "For now, we just set this->session.setContinue(true);")); this->session.setContinue(true); } void NXClientLib::reset() { this->nxsshProcess->terminate(); this->isFinished = false; this->proxyData.encrypted = false; this->password = false; this->session.resetSession(); } void NXClientLib::loginFailed() { this->externalCallbacks->write (NXCL_LOGIN_FAILED, _("Got \"Login Failed\"")); this->isFinished = true; this->nxsshProcess->terminate(); } void NXClientLib::processParseStdout() { string message = nxsshProcess->readAllStandardOutput(); this->externalCallbacks->stdoutSignal (message); dbgln ("NXClientLib::processParseStdout() called"); int response = 0; // Message 211 is sent if ssh is asking to continue with an unknown host if ((response = session.parseResponse(message)) == 211) { this->requestConfirmation (message); } dbgln ("NXClientLib::processParseStdout(): response = " << response); if (response == 100000) { // A program never started. this->isFinished = true; return; } else if (response > 100000) { dbgln ("A process crashed or exited"); int pid = response - 100000; if (this->nxsshProcess->getPid() == pid) { this->nxsshProcess->setError(NOTQPROCCRASHED); this->externalCallbacks->error (_("nxsshProcess crashed or exited")); this->isFinished = true; } else if (this->nxproxyProcess->getPid() == pid) { this->nxproxyProcess->setError(NOTQPROCCRASHED); this->externalCallbacks->error (_("nxproxyProcess crashed or exited")); this->isFinished = true; } else { this->externalCallbacks->error (_("Warning: Don't know what crashed " "(in processParseStdout())")); } return; } // If message 204 is picked, that's authentication failed. if (response == 204) { this->externalCallbacks->write (NXCL_AUTH_FAILED, _("Got \"Authentication Failed\" from nxssh.\n" "Please check the certificate for the first SSL " "authentication stage,\n" "in which the \"nx\" user is authenticated.")); this->isFinished = true; return; } // 147 is server capacity reached if (response == 147) { this->externalCallbacks->serverCapacitySignal(); this->isFinished = true; return; } dbgln ("NXClientLib::processParseStdout(): The message is '" + message + "'(msg end)"); dbgln ("...and response is " << response); notQtUtilities::ensureUnixNewlines (message); list msglist; list::iterator msgiter; notQtUtilities::splitString (message, '\n', msglist); for (msgiter = msglist.begin(); msgiter != msglist.end(); msgiter++) { dbgln ("NXClientLib::processParseStdout(): Processing the message '" + (*msgiter) + "'(end msg)"); // On some connections this is sent via stdout instead of stderr? if (proxyData.encrypted && readyForProxy && ((*msgiter).find("NX> 999 Bye")!=string::npos)) { // This is "NX> 299 Switching connection to: " in // version 1.5.0. This was changed in nxssh version // 2.0.0-8 (see the nxssh CHANGELOG). string switchCommand = "NX> 299 Switch connection to: "; stringstream ss; ss << "127.0.0.1:" << proxyData.port << " cookie: " << proxyData.cookie << "\n"; switchCommand += ss.str(); this->write (switchCommand); } else if ((*msgiter).find ("NX> 287 Redirected I/O to channel descriptors") != string::npos) { this->externalCallbacks->write (287, _("The session has been started successfully")); this->externalCallbacks->connectedSuccessfullySignal(); this->sessionRunning = true; } if ((*msgiter).find("Password") != string::npos) { this->externalCallbacks->write (NXCL_AUTHENTICATING, _("Authenticating with NX server")); this->password = true; } if (!readyForProxy) { string msg = session.parseSSH (*msgiter); if (msg == "204\n" || msg == "147\n") { // Auth failed. dbgln ("NXClientLib::processParseStdout: Got auth failed" " or capacity reached, calling this->parseSSH."); msg = this->parseSSH (*msgiter); } if (msg.size() > 0) { this->write (msg); } } else { this->write (this->parseSSH (*msgiter)); } } return; } void NXClientLib::processParseStderr() { string message = nxsshProcess->readAllStandardError(); dbgln ("In NXClientLib::processParseStderr for message: '" + message + "'(msg end)"); this->externalCallbacks->stderrSignal (message); // Now we need to split the message if necessary based on the // \n or \r characters notQtUtilities::ensureUnixNewlines (message); list msglist; list::iterator msgiter; notQtUtilities::splitString (message, '\n', msglist); for (msgiter=msglist.begin(); msgiter!=msglist.end(); msgiter++) { dbgln ("NXClientLib::processParseStderr: Processing the message '" + (*msgiter) + "'(end msg)"); if (proxyData.encrypted && readyForProxy && ((*msgiter).find("NX> 999 Bye") != string::npos)) { string switchCommand = "NX> 299 Switch connection to: "; stringstream ss; ss << "127.0.0.1:" << proxyData.port << " cookie: " << proxyData.cookie << "\n"; switchCommand += ss.str(); this->write(switchCommand); } else if ((*msgiter).find ("NX> 287 Redirected I/O to channel descriptors") != string::npos) { this->externalCallbacks->write (287, _("The session has been started successfully")); this->externalCallbacks->connectedSuccessfullySignal(); } else if ((*msgiter).find ("NX> 209 Remote host identification has changed") != string::npos) { this->externalCallbacks->write(209, _("SSH Host Key Problem")); this->isFinished = true; } else if ((*msgiter).find ("NX> 280 Ignoring EOF on the monitored channel") != string::npos) { this->externalCallbacks->write (280, _("Got \"NX> 280 Ignoring EOF on the monitored channel\"" " from nxssh...")); this->isFinished = true; } else if ((*msgiter).find ("Host key verification failed") != string::npos) { this->externalCallbacks->write (NXCL_HOST_KEY_VERIFAILED, _("SSH host key verification failed")); this->isFinished = true; } } } void NXClientLib::write (string data) { if (data.size() == 0) { return; } dbgln ("Writing '" << data << "' to nxssh process."); this->nxsshProcess->writeIn(data); if (password) { data = "********"; password = false; } // Output this to the user via a signal - this is data going in to nxssh. this->externalCallbacks->stdinSignal (data); } void NXClientLib::doneAuth() { if (this->keyFile != NULL) { this->keyFile->remove(); delete this->keyFile; } return; } void NXClientLib::allowSSHConnect (bool auth) { session.setContinue (auth); } void NXClientLib::setSessionData (NXSessionData *nxSessionData) { session.setSessionData (nxSessionData); string a = "NX> 105"; string d = session.parseSSH(a); if (d.size()>0) { this->write(d); } } void NXClientLib::runSession () { session.runSession(); string a = "NX> 105"; string d = session.parseSSH(a); if (d.size()>0) { this->write(d); } } string NXClientLib::parseSSH (string message) { string rMessage; string::size_type pos; rMessage = ""; dbgln ("NXClientLib::parseSSH called for message '" + message + "'"); if ((pos = message.find("NX> 700 Session id: ")) != string::npos) { this->externalCallbacks->write (700, _("Got a session ID")); proxyData.id = message.substr(pos+20, message.length()-pos); } else if ((pos = message.find("NX> 705 Session display: ")) != string::npos) { stringstream portss; int portnum; portss << message.substr(pos+25, message.length()-pos); portss >> portnum; proxyData.display = portnum; proxyData.port = portnum + 4000; } else if ((pos = message.find("NX> 706 Agent cookie: ")) != string::npos) { proxyData.cookie = message.substr(pos+22, message.length()-pos); this->externalCallbacks->write (706, _("Got an agent cookie")); } else if ((pos = message.find("NX> 702 Proxy IP: ")) != string::npos) { proxyData.proxyIP = message.substr(pos+18, message.length()-pos); this->externalCallbacks->write (702, _("Got a proxy IP")); } else if (message.find("NX> 707 SSL tunneling: 1") != string::npos) { this->externalCallbacks->write (702, _("All data will be SSL tunnelled")); proxyData.encrypted = true; } else if (message.find("NX> 147 Server capacity") != string::npos) { this->externalCallbacks->write (147, _("Got \"Server Capacity Reached\" from nxssh.")); this->externalCallbacks->serverCapacitySignal(); this->isFinished = true; } else if (message.find ("NX> 204 Authentication failed.") != string::npos) { this->externalCallbacks->write (204, _("NX SSH Authentication Failed, finishing")); this->isFinished = true; } if (message.find("NX> 710 Session status: running") != string::npos) { this->externalCallbacks->write (710, _("Session status is \"running\"")); invokeProxy(); session.wipeSessions(); rMessage = "bye\n"; } return rMessage; } void NXClientLib::invokeProxy() { this->externalCallbacks->write (NXCL_INVOKE_PROXY, _("Starting NX session")); #if NXCL_CYGWIN NXSessionData* sessionData = getSession()->getSessionData(); string res; if (sessionData->geometry == "fullscreen") { stringstream resolution; ostringstream dimensionX, dimensionY; dimensionX << sessionData->xRes; dimensionY << sessionData->yRes; resolution << dimensionX.str() << "x" << dimensionY.str(); res = resolution.str(); } else { res = sessionData->geometry; } startX11(res, ""); #endif #if NXCL_DARWIN // Let's run open -a X11 to fire up X list x11Arguments; x11Arguments.push_back("open"); x11Arguments.push_back("-a"); x11Arguments.push_back("X11"); string openPath = this->getPath("open"); this->x11Process->start(openPath, x11Arguments); this->x11Probe = true; if (this->x11Process->waitForStarted() == false) { this->externalCallbacks->write (NXCL_PROCESS_ERROR, _("Error starting X11!")); this->isFinished = true; } this->x11Probe = false; // Horrendous hack - must fix for (int i = 0; i < 32768; i++) {}; #endif int e; char * home; home = getenv ("HOME"); stringstream ss; ss << home; string nxdir = ss.str(); nxdir += "/.nx"; // Create the .nx directory first. if (mkdir (nxdir.c_str(), 0770)) { e = errno; if (e != EEXIST) { // We don't mind .nx already // existing, though if there is a // _file_ called $HOME/.nx, we'll // get errors later. this->externalCallbacks->error (_("Problem creating .nx directory")); } } // Now the per session directory nxdir += "/S-" + proxyData.id; if (mkdir (nxdir.c_str(), 0770)) { e = errno; if (e != EEXIST) { // We don't mind .nx already this->externalCallbacks->error (_("Problem creating Session directory")); } } string x11Display = ""; #if NXCL_DARWIN || NXCL_CYGWIN x11Display = ",display=:0.0"; #endif stringstream data; if (proxyData.encrypted) { data << "nx/nx" << x11Display << ",session=session,encryption=1,cookie=" << proxyData.cookie << ",id=" << proxyData.id << ",listen=" << proxyData.port << ":" << proxyData.display << "\n"; // may also need shmem=1,shpix=1,font=1,product=... } else { // Not tested yet data << "nx/nx" << x11Display << ",session=session,cookie=" << proxyData.cookie << ",id=" << proxyData.id // << ",connect=" << proxyData.server << ":" << proxyData.display << ",listen=" << proxyData.port << ":" << proxyData.display << "\n"; } // Filename is nxdir plus "/options" nxdir += "/options"; std::ofstream options; options.open (nxdir.c_str(), std::fstream::out); options << data.str(); options.close(); // Build arguments for the call to the nxproxy command list arguments; arguments.push_back("nxproxy"); // argv[0] has to be the program name arguments.push_back("-S"); ss.str(""); ss << "options=" << nxdir; ss << ":" << proxyData.display; arguments.push_back(ss.str()); // Find a path for the nxproxy process using getPath() string nxproxyPath = this->getPath ("nxproxy"); this->nxproxyProcess->start(nxproxyPath, arguments); if (this->nxproxyProcess->waitForStarted() == false) { this->externalCallbacks->write (NXCL_PROCESS_ERROR, _("Error starting nxproxy!")); this->isFinished = true; } } void NXClientLib::startX11 (string resolution, string name) { #if NXCL_CYGWIN // Invoke NXWin.exe on Windows machines // See if XAUTHORITY path is set stringstream xauthority; xauthority << getenv("HOME") << "/.Xauthority"; // Now we set the environment variable setenv("XAUTHORITY", xauthority.str().c_str(), 1); // Now we actually start NXWin.exe list nxwinArguments; // Arguments taken from 2X nxwinArguments.push_back("NXWin"); nxwinArguments.push_back("-nowinkill"); nxwinArguments.push_back("-clipboard"); nxwinArguments.push_back("-noloadxkb"); nxwinArguments.push_back("-agent"); nxwinArguments.push_back("-hide"); nxwinArguments.push_back("-noreset"); nxwinArguments.push_back("-nolisten"); nxwinArguments.push_back("tcp"); // TODO: If rootless, append "-multiwindow" and "-hide" but only // hide if not restoring // Now we set up the font paths. By default this is $NX_SYSTEM/usr/X11R6/... stringstream fontPath; fontPath << getenv("NX_SYSTEM") << "/X11R6/lib/X11/fonts/base," << getenv("NX_SYSTEM") << "/X11R6/lib/X11/fonts/TTF"; nxwinArguments.push_back("-fp"); nxwinArguments.push_back(fontPath.str()); nxwinArguments.push_back("-name"); nxwinArguments.push_back("NXWin"); nxwinArguments.push_back(":0"); nxwinArguments.push_back("-screen"); nxwinArguments.push_back("0"); nxwinArguments.push_back(resolution); nxwinArguments.push_back(":0"); nxwinArguments.push_back("-nokeyhook"); string nxwinPath = this->getPath("nxwin"); this->x11Process->start(nxwinPath, nxwinArguments); this->x11Probe = true; if (this->x11Process->waitForStarted() == false) { this->externalCallbacks->write (NXCL_PROCESS_ERROR, _("Error starting nxwin!")); this->isFinished = true; } this->x11Probe = false; list nxauthArguments; char hostname[256]; gethostname(hostname, 256); string cookie = getSession()->generateCookie(); cookie.resize(32); stringstream domain; domain << hostname << "/unix:0"; // These arguments taken from the 2X GPL client // We're going to assume that nxauth is in PATH nxauthArguments.push_back("nxauth"); nxauthArguments.push_back("-i"); nxauthArguments.push_back("-f"); nxauthArguments.push_back(xauthority.str()); nxauthArguments.push_back("add"); nxauthArguments.push_back(domain.str()); nxauthArguments.push_back("MIT-MAGIC-COOKIE-1"); nxauthArguments.push_back(cookie); this->nxauthProcess->setCallbacks (&callbacks); string nxauthPath = this->getPath("nxauth"); this->nxauthProcess->start(nxauthPath, nxauthArguments); if (this->nxauthProcess->waitForStarted() == false) { this->externalCallbacks->write (NXCL_PROCESS_ERROR, _("Error starting nxauth!")); this->isFinished = true; } #endif } bool NXClientLib::chooseResumable (int n) { return (this->session.chooseResumable(n)); } bool NXClientLib::terminateSession (int n) { return (this->session.terminateSession(n)); } string NXClientLib::getPath (string prog) { string path; struct stat * buf; buf = static_cast(malloc (sizeof (struct stat))); if (!buf) { // Malloc error. return prog; } // We'll check the custom search path first stringstream pathTest; pathTest << customPath << "/" << prog; memset (buf, 0, sizeof(struct stat)); stat (pathTest.str().c_str(), buf); if (S_ISREG (buf->st_mode) || S_ISLNK (buf->st_mode)) { // Found in custom path free(buf); return pathTest.str(); } path = PACKAGE_BIN_DIR"/" + prog; memset (buf, 0, sizeof(struct stat)); stat (path.c_str(), buf); if (S_ISREG (buf->st_mode) || S_ISLNK (buf->st_mode)) { // Found prog in PACKAGE_BIN_DIR } else { path = "/usr/local/bin/" + prog; memset (buf, 0, sizeof(struct stat)); stat (path.c_str(), buf); if (S_ISREG (buf->st_mode) || S_ISLNK (buf->st_mode)) { // Found prog in /usr/local/bin } else { path = "/usr/bin/" + prog; memset (buf, 0, sizeof(struct stat)); stat (path.c_str(), buf); if (S_ISREG (buf->st_mode) || S_ISLNK (buf->st_mode)) { // Found prog in /usr/bin } else { path = "/usr/NX/bin/" + prog; memset (buf, 0, sizeof(struct stat)); stat (path.c_str(), buf); if (S_ISREG (buf->st_mode) || S_ISLNK (buf->st_mode)) { } else { path = "/bin/" + prog; memset (buf, 0, sizeof(struct stat)); stat (path.c_str(), buf); if (S_ISREG (buf->st_mode) || S_ISLNK (buf->st_mode)) { // Found prog in /bin } else { // Just return the // prog name. path = prog; } } } } } free (buf); return path; } //@} nxcl-0.9/configure.ac0000644000175000017500000000652110764221506013273 0ustar mjj29mjj29dnl Process this file with autoconf to produce a configure script. AC_PREREQ(2.59c) AC_INIT([nxcl], [1.0], [seb@esfnet.co.uk]) AC_CONFIG_SRCDIR(nxcl/nxcl.cpp) AC_REVISION([$Revision: 1.3 $]) AC_PREFIX_DEFAULT(/usr/local) AM_INIT_AUTOMAKE([1.10 foreign]) AM_CONFIG_HEADER(config.h) AM_MAINTAINER_MODE AC_LANG_CPLUSPLUS dnl Checks for programs. AC_PROG_CXX AC_PROG_CC AC_PROG_INSTALL AC_PROG_LIBTOOL dnl check for boost library dnl I would prefer to include boost code and compile in place and statically link. dnl AC_CHECK_LIB(boost_signals, LIB_BOOST_SIGNALS="-lboost_signals") dnl AC_SUBST(LIB_BOOST_SIGNALS) AC_ARG_WITH(nxcmd, AC_HELP_STRING([--with-nxcmd], [build nxcmd]), [with_nxcmd=${withval}], [with_nxcmd=auto]) AS_IF([test "$with_nxcmd" != no], [ PKG_CHECK_MODULES(DBUS, [ dbus-1 ], [with_nxcmd=yes], [ AS_IF([test "$with_nxcmd" = yes], [ AC_MSG_ERROR([nxcmd support was requested but D-Bus libraries are not available]) ]) with_nxcmd=no ]) ]) AM_CONDITIONAL(WITH_NXCMD, test "$with_nxcmd" = yes) AC_ARG_WITH(doxygen, AC_HELP_STRING([--with-doxygen], [build doxygen API documentation]), [with_doxygen=${withval}], [with_doxygen=yes]) if test "$with_doxygen" = yes; then AC_CHECK_PROG(DOXYGEN, doxygen, doxygen, /bin/echo) fi AM_CONDITIONAL(WITH_DOXYGEN, test "$with_doxygen" = yes) dnl Checks for library functions. AC_HEADER_STDC AC_HEADER_TIME AC_CHECK_FUNCS(strftime gettimeofday uname) dnl Determine host system type AC_CANONICAL_HOST AC_DEFINE_UNQUOTED(HOST, "$host", [The host system nxcl was configured for]) dnl pkg_modules="libxml2" <- Check this and modify when necessary dnl PKG_CHECK_MODULES(PACKAGE, [$pkg_modules]) AC_SUBST(PACKAGE_CFLAGS) AC_SUBST(PACKAGE_LIBS) dnl enable/disable compiler warnings (using gcc), if specified AC_ARG_ENABLE(warnings, [ --disable-warnings disable gcc warnings [default=no]], [case "${enableval}" in yes) nxcl_warnings=yes ;; no) nxcl_warnings=no ;; *) AC_MSG_ERROR(bad value ${enableval} for --enable-warnings) ;; esac], nxcl_warnings=yes) AC_MSG_CHECKING(whether to use gcc verbose warnings) AC_MSG_RESULT($nxcl_warnings) if (test "$nxcl_warnings" = yes && test "$GCC" = yes); then CXXFLAGS="-Wall $CXXFLAGS" fi dnl enable/disable debug logging, if specified AC_ARG_ENABLE(debug-output, [ --enable-debug-output enable debug output [default=no]], [case "${enableval}" in yes) nxcl_debug=yes ;; no) nxcl_debug=no ;; *) AC_MSG_ERROR(bad value ${enableval} for --enable-debug-output) ;; esac], nxcl_debug=no) AC_MSG_CHECKING(whether to enable debugging output) AC_MSG_RESULT($nxcl_debug) AM_CONDITIONAL(DEBUG, test "$nxcl_debug" = yes) dnl Do some platform checking for cygwin if test "$(uname -o)" = Cygwin; then AC_DEFINE(NXCL_CYGWIN, 1, Define if compiling on Cygwin) else AC_DEFINE(NXCL_CYGWIN, 0, Define if compiling on Cygwin) fi dnl Do some platform checking for OS X if test "$(uname)" = Darwin; then AC_DEFINE(NXCL_DARWIN, 1, Define if compiling on Darwin) else AC_DEFINE(NXCL_DARWIN, 0, Define if compiling on Darwin) fi dnl Add in doc/Makefile to this: AC_CONFIG_FILES([Makefile lib/Makefile nxcl/Makefile test/Makefile doc/Makefile nxcl.pc]) AC_OUTPUT nxcl-0.9/Makefile.am0000644000175000017500000000057110764221506013040 0ustar mjj29mjj29 AUTOMAKE_OPTIONS = check-news dist-bzip2 ALWAYS_SUBDIRS = lib test SUBDIRS = $(ALWAYS_SUBDIRS) if WITH_NXCMD SUBDIRS += nxcl endif if WITH_DOXYGEN SUBDIRS += doc endif CLEANFILES = *~ MAINTAINERCLEANFILES = aclocal.m4 nxcl-*.tar.gz nxcl-*.tar.bz2 nxcl-*.diff INCLUDES = -I./lib pkgconfigdir = $(libdir)/pkgconfig pkgconfig_DATA = nxcl.pc EXTRA_DIST = nxcl.pc.in nxcl-0.9/nxcl.pc.in0000644000175000017500000000037210764221506012700 0ustar mjj29mjj29# nxcl pkg-config source file prefix=@prefix@ exec_prefix=@exec_prefix@ libdir=@libdir@ includedir=@includedir@/nxcl Name: nxcl Description: NX client library Version: @VERSION@ Requires: Conflicts: Libs: -L${libdir} -lnxcl Cflags: -I${includedir} nxcl-0.9/README0000644000175000017500000000541010764221506011661 0ustar mjj29mjj29 nxcl: A library for building NX clients. Seb James. July-September 2007. seb@esfnet.co.uk Based on nxclientlib by George Wright, but with all dependencies on Qt removed and the Qt build system replaced with GNU autotools. doxygen is required if you want to build source documentation. The library code is in nxcl-release/lib/. A binary, called nxcl - the "nxcl dbus daemon" is built in nxcl-release/nxcl/. nxcl links to libnxcl and can negotiate an nx connection. nxcl-release/test/ contains some test programs. notQtTest tests some of the features of the notQt classes in nxcl-release/lib/. libtest is a simple command line NX client linking straight to the libnxcl library. nxcmd is a second command line NX client, but it launches nxcl, then sends session data there and allows nxcl to negotiate the NX connection. This could be extended into quite a complete command line NX client. A GTK+ NX client called nxlaunch is distributed separately. Nxlaunch uses the nxcl daemon, though it would be quite possible to write a GTK client which links directly to the nxcl library. You should study nxcmd.cpp and nxlaunch if you are interested in writing an NX client using a different widget system (say Windows, Qt, Tk, etc) which uses the Nxcl dbus daemon. Look at nxcl.cpp/h if you want to write an NX client which links directly to libnxcl. Building nxcl ------------- Prerequisites are: * libXcomp from NoMachine, provided by the nxcomp package. * nxssh from NoMachine * nxproxy from NoMachine (These three NX components all should be from the 3.0.0 series. You can obtain them from NoMachine's servers at http://www.nomachine.com/sources.php) And (only) for the standalone dbus client you'll need: * libdbus-1 - http://dbus.freedesktop.org/ Note that you'll need the dbus daemon to be running to use the nxcl standalone binary, but NOT if you link your client directly to libnxcl.so* The D-Bus client can be disabled with the --without-nxcmd flag to configure. If you have doxygen on your system, (imperfect) documentation will be generated from the source header files. Documentation can be disabled with the --without-doxygen flag to configure. Compile and install libXcomp, nxssh and nxproxy following the instructions in the readme file for each package. You can install the nxssh and nxproxy in any of the following locations: /bin /usr/bin /usr/local/bin /usr/NX/bin _or_ the same place that you will install the nxcl binary, determined from your --prefix directive to the configure script. If you checked out the svn code, you need to do: autoreconf -is to create the configure script (from configure.ac) and the Makefiles (from the Makefile.am files). Then configure, make and install in the usual way: ./configure [--enable-debug-output] [--prefix=/opt/myNXstuff] make make install