1 /* Copyright (C) 2000-2004  Thomas Bopp, Thorsten Hampel, Ludger Merkens
     3  *  This program is free software; you can redistribute it and/or modify
     4  *  it under the terms of the GNU General Public License as published by
     5  *  the Free Software Foundation; either version 2 of the License, or
     6  *  (at your option) any later version.
     8  *  This program is distributed in the hope that it will be useful,
     9  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
    10  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    11  *  GNU General Public License for more details.
    13  *  You should have received a copy of the GNU General Public License
    14  *  along with this program; if not, write to the Free Software
    15  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
    17  * $Id: client_base.pike,v 1.1 2008/03/31 13:39:57 exodusd Exp $
    19 inherit "kernel/socket";
    20 inherit "net/coal/binary";
    24 class client_base : public socket,binary{
    31 private  mapping        mObjects; // objects
    32 private  string      sLastPacket; // last package while communicating
    33 private  int                iOID; // the object id of the current object
    34 private  int                iTID; // the current transaction id
    36          mapping      mVariables; // session variables
    41          function  downloadStore;
    43 private  mixed          miResult;
    44 private  int           miCommand;
    47  Thread.Mutex    cmd_mutex =     Thread.Mutex();
    48  Thread.Mutex    newmut =     Thread.Mutex();
    49  Thread.Condition cmd_cond = Thread.Condition();
    50  Thread.Queue      resultQueue = Thread.Queue();
    51  Thread.MutexKey newmutkey;
    52  Thread.Condition    th = Thread.Condition();
    55 string connected_server;
    62   private  string identifier = 0;
    64   private  int(0..1) nowait;
    65   private  mapping(string:function) functions=([]);
    71   object get_environment() {
    72     return send_command(COAL_COMMAND, ({ "get_environment" }));
    75   int get_object_class() {
    78       int id = set_object(oID);
    79       mixed res = send_command(COAL_COMMAND, ({ "get_object_class" }));
    88     return 1; //PSTAT_SAVE_OK
    91   string get_identifier() {
    92     if ( !stringp(identifier) ) {
    94       int id = set_object(oID);
    95       identifier = send_command(COAL_COMMAND, ({ "get_identifier" }));
   102   void create(int id) {
   106   int no_wait(void|int(0..1) _nowait)
   108     if(!zero_type(_nowait) && nowait == !_nowait)
   117   string function_name(function fun)
   119     return search(functions, fun);
   124     mixed result = catch {
   125     if(this_object()->__indices)
   126       return this_object()->__indices();
   135     catch{ describe=`->("describe")(); };
   137     if ( stringp(connected_server) ) format += "%s:";
   138     else format += "%O:";
   139     if ( intp(connected_port) ) format += "%d/";
   140     else format += "%O/";
   141     if ( stringp(describe) ) format += "%s";
   143     return sprintf( format, connected_server, connected_port, describe );
   146   function `->(string fun) 
   152       if ( fun == "exec_code" )
   154       else if ( fun == "serialize_coal" )
   157         functions[fun]=lambda(mixed|void ... args)
   159                          return send_cmd(oID, fun, args, nowait); 
   161       return functions[fun];
   164   function find_function(string fun) {
   166       functions[fun]=lambda(mixed|void ... args)
   168                   return send_cmd(oID, fun, args, nowait); 
   170     return functions[fun];
   182 int set_object(int|object id)
   187    iOID = id->get_object_id();
   201  object find_obj(int id)
   203     if ( !mObjects[id] ) {
   204    mObjects[id] = SteamObj(id);
   205    //werror("Created:"+master()->describe_object(mObjects[id])+"\n");
   212 object find_object(int id) { return find_obj(id); }
   222 int connect_server(string server, int port)
   235     if ( connect(server, port) ) {
   236    MESSAGE("Connected to " + server + ":"+port +"\n");
   237    connected_server=server;
   239    __last_response = time(); // timestamp of last response 
   241    set_buffer(65536, "r");
   242    set_buffer(65536, "w");
   244    thread_create(read_thread);
   255  int write(string str)
   257     __last_response = time();
   271 void read_callback(object id, string data)
   273     __last_response = time();
   275     if ( functionp(downloadStore) ) {
   279    __downloadBytes -= strlen(data);
   280    if ( __downloadBytes <= 0 ) {
   282        downloadStore = 0; // download finished
   287     if ( __downloadBytes > 0 ) {
   288    if ( __downloadBytes <= strlen(sLastPacket) )
   289        resultQueue->write(sLastPacket);
   293     mixed res = receive_binary(sLastPacket);
   298    sLastPacket = res[2];
   299    if ( tid == iWaitTID ) {
   301        miCommand = res[0][1];
   302        resultQueue->write(miResult);
   307 string download(int bytes, void|function store) 
   309     // actually the last command should have been the upload response,
   310     // so there shouldnt be anything on the line except events
   311     // which should have been already processed
   312     // everything else should be download data
   314     __downloadBytes = bytes;
   316     if ( functionp(store) ) {
   317    data = copy_value(sLastPacket[..bytes]);
   318    __downloadBytes -= strlen(data);
   319    if ( strlen(data) > 0 )
   321    if ( __downloadBytes <= 0 ) {
   325    downloadStore = store;
   330     if ( strlen(sLastPacket) >= bytes ) {
   331    data = copy_value(sLastPacket[..bytes]);
   332    if ( bytes > strlen(sLastPacket) )
   333        sLastPacket = sLastPacket[bytes+1..];
   340     miResult = resultQueue->read();
   341     data = copy_value(sLastPacket[..bytes]);
   342     if ( strlen(sLastPacket) > bytes )
   343    sLastPacket = sLastPacket[bytes+1..];
   357 void handle_error(mixed err)
   369 mixed send_command(int cmd, array args, int|void no_wait)
   371 //    newmutkey = newmut->lock(1);
   372     if ( !no_wait ) iWaitTID = iTID;
   375     string msg = coal_compose(iTID++, cmd, iOID, 0, args);
   376     string nmsg = copy_value(msg);
   379     if ( no_wait ) return 0;
   382     Thread.Thread(check_thread); 
   383     result = resultQueue->read();
   386     if ( miCommand == COAL_ERROR ) {
   387    handle_error(result);
   394     int start_time = time();
   395     th->wait(cmd_mutex->lock(), 10);
   396     if((time()-start_time) >=10){
   397       resultQueue->write("sTeam connection lost.");
   410 mixed send_cmd(object|int obj, string func, mixed|void args, void|int no_wait)
   412     int oid = set_object(obj);
   413     if ( zero_type(args) )
   415     else if ( !arrayp(args) )
   418     mixed res = send_command(COAL_COMMAND, ({ func, args }), no_wait);
   431 login(string name, string pw, int features, string|void cname, int|void novars)
   433     if ( !stringp(cname) )
   434    cname = "steam-pike";
   438    loginData =send_command(COAL_LOGIN, ({ name, pw, cname, features, __id }));
   441        send_command(COAL_LOGIN,({ name, pw, cname,CLIENT_FEATURES_ALL, __id}));
   443     if ( arrayp(loginData) && sizeof(loginData) >= 9 ) {
   444    mVariables["user"] = iOID;
   445    foreach ( indices(loginData[8]), string key ) {
   446        mVariables[key] = loginData[8][key];
   448    mVariables["rootroom"] = loginData[6];
   451        foreach ( values(loginData[9]), object cl ) {
   452            set_object(cl->get_object_id());
   453            mVariables[send_cmd(cl,"get_identifier")] = cl;
   463     werror("logout()!!!\n\n");
   465     write(coal_compose(0, COAL_LOGOUT, 0, 0, 0));
   471     resultQueue->write("");
   476 void write_error2file(mixed|string err, int recursive) {
   478     Stdio.File error_file;
   484     directory = get_dir(path);
   487         tmp_found=Stdio.exist(path+"/install_error."+file_counter);
   489             file_counter = file_counter + 1;
   497         file_counter = file_counter -1;
   498     error_file=Stdio.File (path+"/install_error."+file_counter ,"cwa");
   500         error_file->write(err);
   503         foreach(err, mixed error){
   504             if ( stringp(error) || intp(error) )
   505                 error_file->write((string)error);
   506             else if ( objectp(error) )
   507                 error_file->write("<object...>\n");
   508             else if ( arrayp(error) ){
   509                 write_error2file(error,1);