/* This file is part of Bolixo. Bolixo 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 3 of the License, or (at your option) any later version. Bolixo is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Bolixo. If not, see . */ /* Command line tool to manipulate the bolixo file-system. The program works like normal Linux commands. It is general. For example, it -can copy from bolixo to bolixo -bolixo to linux -linux to bolixo -linux to linux bofs cp ... bofs ls Further, if the program is renamed bocp (normally done using a symlink), it acts as "bofs cp" */ #include #include #include #include #include #include #include #include #include #include #include #include #define DEFINE_TBTYPE #define DEFINE_TBFTYPE #include "bolixo.h" #include "bolixo.m" #include #include "filesystem.h" #include "helper.h" #include "instrument.h" static DEBUG_KEY D_SIGN("sign","Signature validation"); using namespace std; #define bod_client_adduser_NOTNEED #define bod_client_confirmuser_NOTNEED #define bod_client_deleteuser_NOTNEED #define bod_client_confirmdelete_NOTNEED #define bod_client_addfile_NOTNEED #define bod_client_modifyfile_NOTNEED #define bod_client_readfile_NOTNEED #define bod_client_sendattach_NOTNEED #define bod_client_form_readvar_NOTNEED #define bod_client_form_savevar_NOTNEED #define bod_client_form_deletevar_NOTNEED #define bod_client_form_deleteall_NOTNEED #define bod_client_public_checkuser_NOTNEED #define bod_client_systempubkey_NOTNEED #define bod_client_registernode_NOTNEED #define bod_client_remotelogin_NOTNEED #define bod_client_remotepass_NOTNEED #define bod_client_nodelogin_NOTNEED #define bod_client_nodepass_NOTNEED #define bod_client_remote_interest_set_NOTNEED #define bod_client_remote_interest_unset_NOTNEED #include "proto/bod_client.protoch" #define webapi_test_NOTNEED #define webapi_addfile_NOTNEED #define webapi_modifyfile_NOTNEED #define webapi_rename_NOTNEED #define webapi_readfile_NOTNEED #define webapi_set_access_NOTNEED #define webapi_markview_NOTNEED #define webapi_sendattach_NOTNEED #define webapi_registernode_NOTNEED #define webapi_remotelogin_NOTNEED #define webapi_remotepass_NOTNEED #define webapi_nodelogin_NOTNEED #define webapi_nodepass_NOTNEED #define webapi_remote_interest_set_NOTNEED #define webapi_remote_interest_unset_NOTNEED #include "proto/webapi.protoch" #include "proto/bolixod_client.protodef" #include "proto/bolixoapi.protoch" static bool verbose = false; static bool testmode = false; static TRANS_NOTLOAD *tbviewed[]={P_MSG_U(I_VIEWNEW,"New"),P_MSG_U(I_VIEWSEEN,"Seen"),P_MSG_U(I_VIEWCHANGED,"Changed")}; static void notdone() { tlmp_error ("Sorry, not done yet!\n"); } static const char *normalize_date (PARAM_STRING date) { const char *ret = NULL; if (testmode){ static map dates; string tmp; if (strlen(date.ptr)==19){ tmp = string(date.ptr,17); }else{ tmp = date.ptr; } auto d = dates.find(tmp); if (d == dates.end()){ static int datecount = 0; // Invent a different date; time_t t = datecount; datecount++; struct tm *tt = localtime(&t); auto &d = dates[tmp] = string_f("%04d/%02d/%02d %02d:%02d:%02d" ,tt->tm_year+1900,tt->tm_mon+1,tt->tm_mday ,tt->tm_hour,tt->tm_min,tt->tm_sec); ret = d.c_str(); }else{ ret = d->second.c_str(); } }else{ ret = date.ptr; } return ret; } static unsigned normalize_size (unsigned size) { unsigned ret = size; if (size > 0 && testmode){ static map sizes; auto d = sizes.find(size); if (d == sizes.end()){ static unsigned alloc_size=1000; sizes[size] = alloc_size; ret = alloc_size; alloc_size++; }else{ ret = d->second; } } return ret; } static map uuids; static void load_normalize_uuids(const char *fname) { (fname,true); vector tb; if (str_splitline(line,' ',tb)==2){ uuids[tb[0]] = atoi(tb[1].c_str()); } return 0; } static string normalize_uuid(const char *s) { if (*s == '\0'){ return string(); }else if (testmode){ unsigned num = 0; auto uu = uuids.find(s); if (uu == uuids.end()){ num = uuids.size(); uuids[s] = num; }else{ num = uu->second; } return string_f ("uuid-%04u",num); }else{ return string(s); } } static void bofs_maxlen (PARAM_STRING s, unsigned &max_s) { unsigned len = strlen(s.ptr); if (len > max_s) max_s = len; } static string bod_createsession(CONNECT_INFO &con) { glocal string ret; (con); glocal.ret = sessionid; return glocal.ret; } __attribute__((format(printf, 3, 4))) static void bofs_error (const char *cmd, bool internal_error, const char *msg, ...) { va_list list; va_start (list,msg); char buf[1000]; vsnprintf (buf,sizeof(buf)-1,msg,list); va_end (list); if (internal_error){ tlmp_error ("bofs %s: Internal/protocol error, %s\n",cmd,buf); }else{ tlmp_error ("bofs %s: %s\n",cmd,buf); } } static int bofs_login ( CONNECT_INFO &con, PARAM_STRING email, PARAM_STRING password, string &sessionid) // Session ID for the internal protocol { glocal int ret = 0; glocal const char *email = email.ptr; if (con.port.size() > 0){ sessionid = bod_createsession(con); (con,sessionid,email,password); if (!success){ glocal.ret = -1; bofs_error ("login",internal_error,MSG_U(E_LOGIN,"login failed for %s success=%d"),glocal.email,success); } } return glocal.ret; } static bool nonstrict = false; static int bofs_login ( CONNECT_HTTP_INFO &hcon, PARAM_STRING email, PARAM_STRING password, string &hsessionid) // For HTTPS protocol { glocal string *hsessionid = &hsessionid; glocal int ret = 0; glocal const char *email = email.ptr; if (hcon.host.size() > 0){ if (nonstrict) hcon.setnonstrictmode(); (hcon,email,password); if (success){ (*glocal.hsessionid) = sessionid; }else{ bofs_error ("webapi login",internal_error,MSG_U(E_HTTPLOGIN,"HTTP login failed for %s success=%d"),glocal.email,success); glocal.ret = -1; } } return glocal.ret; } static void bofs_logout (CONNECT_INFO &con, const PARAM_STRING sessionid) { if (con.port.size() > 0){ (con,sessionid); } } static void bofs_logout (CONNECT_HTTP_INFO &hcon, const PARAM_STRING hsessionid) { if (hcon.host.size() > 0){ (hcon,hsessionid); } } struct CONTEXT{ string email; string user; string password; string sessionid; // Session ID for the internal protocol string hsessionid; // Session ID for the https protocol string threshold; // Date to filter in the history of a directory or files bool preset_session; // We received the session id from the command line // so logout is not needed. CONNECT_INFO con; CONNECT_INFO con_sess; CONNECT_HTTP_INFO hcon; CONTEXT(){ preset_session = false; } ~CONTEXT(){ if (!preset_session){ if (sessionid.size()>0) bofs_logout(con,sessionid); if (hsessionid.size()>0) bofs_logout(hcon,hsessionid); } } int login(){ int ret = -1; if (sessionid.size()>0 || hsessionid.size()>0){ ret = 0; }else if (is_internal()){ ret = bofs_login (con,email,password,sessionid); if (ret == -1) tlmp_error ("bod_login failed\n"); }else{ ret = bofs_login (hcon,email,password,hsessionid); if (ret == -1) tlmp_error ("htbod_login failed\n"); } return ret; } int hlogin(){ int ret = -1; if (hsessionid.size()>0){ ret = 0; }else{ ret = bofs_login (hcon,email,password,hsessionid); if (ret == -1) tlmp_error ("webapi_login failed\n"); } return ret; } bool is_internal(){ return con.port.size() > 0; } }; #define _TLMP_bofs_listdir struct _F_bofs_listdir { #define _F_bofs_listdir_ok(x) void x ok(bool internal_error, bool success, const char *msg, const vector &files) virtual _F_bofs_listdir_ok( )=0; }; static void bofs_listdir(_F_bofs_listdir &c, CONTEXT &ctx, PARAM_STRING name, PARAM_STRING threshold, bool history, unsigned offset, unsigned chunk) { glocal _F_bofs_listdir *c = &c; if (ctx.is_internal()){ (ctx.con,ctx.sessionid,name,threshold,history,offset,chunk); glocal.c->ok(internal_error,success,msg,files); }else{ (ctx.hcon,ctx.hsessionid,name,threshold,history,offset,chunk); glocal.c->ok(internal_error,success,msg,files); } } #define _TLMP_bofs_readfile_bob struct _F_bofs_readfile_bob { #define _F_bofs_readfile_bob_ok(x) void x ok(bool internal_error, bool success, const char *msg, const BOB_TYPE &content, const READINFO_receive &info, const char *handle, bool more) virtual _F_bofs_readfile_bob_ok( )=0; }; static void bofs_readfile_bob(_F_bofs_readfile_bob &c, CONTEXT &ctx, PARAM_STRING path, PARAM_STRING threshold, bool nomore) { glocal _F_bofs_readfile_bob *c = &c; if (ctx.is_internal()){ (ctx.con,ctx.sessionid,path,threshold,nomore); glocal.c->ok(internal_error,success,msg,content,info,handle,more); }else{ (ctx.hcon,ctx.hsessionid,path,threshold,nomore); glocal.c->ok(internal_error,success,msg,content,info,handle,more); } } #define _TLMP_bofs_readmore struct _F_bofs_readmore { #define _F_bofs_readmore_ok(x) void x ok(bool internal_error, bool success, const char *msg, const BOB_TYPE &content, bool more) virtual _F_bofs_readmore_ok( )=0; }; static void bofs_readmore(_F_bofs_readmore &c, CONTEXT &ctx, PARAM_STRING handle) { glocal _F_bofs_readmore *c = &c; if (ctx.is_internal()){ (ctx.con,ctx.sessionid,handle); glocal.c->ok(internal_error,success,msg,content,more); }else{ (ctx.hcon,ctx.hsessionid,handle); glocal.c->ok(internal_error,success,msg,content,more); } } static map pubkeys; static string bofs_pubcachefile() { return string_f("%s/.bofs.pubcache",getenv("HOME")); } static void bofs_loadpubcache() { static bool is_init = false; if (!is_init){ is_init = true; glocal string user; glocal string pubkey; (bofs_pubcachefile(),true); if (line[0] == '#'){ if (glocal.user.size() > 0) pubkeys[glocal.user] = glocal.pubkey; glocal.pubkey.clear(); glocal.user = line+1; }else{ glocal.pubkey += string(line) + "\n"; } return 0; if (glocal.user.size() > 0) pubkeys[glocal.user] = glocal.pubkey; } } #define _TLMP_bofs_getpubkey struct _F_bofs_getpubkey { #define _F_bofs_getpubkey_ok(x) void x ok(bool internal_error, bool success, const char *pubkey) virtual _F_bofs_getpubkey_ok( )=0; }; static void bofs_getpubkey(_F_bofs_getpubkey &c, CONTEXT &ctx, PARAM_STRING nickname) { glocal _F_bofs_getpubkey *c = &c; bofs_loadpubcache(); glocal string user = nickname.ptr; CONNECT_HTTP_INFO hcon = ctx.hcon; bool remote_user = false; const char *pt = strchr(nickname.ptr,'@'); string local_user = nickname.ptr; if (pt==NULL){ glocal.user = string_f("%s@%s",nickname.ptr,ctx.hcon.host.c_str()); }else{ local_user = string(nickname.ptr,pt-nickname.ptr); remote_user = true; hcon.host = pt+1; hcon.port = "443"; hcon.use_ssl = true; if (nonstrict) hcon.setnonstrictmode(); } auto p = pubkeys.find(glocal.user); if (p != pubkeys.end()){ debug_printf (D_SIGN,"Pubkey for user %s found in cache\n",glocal.user.c_str()); c.ok(false,true,p->second.c_str()); }else{ ("/dev/tty",false); fprintf (fout,MSG_U(I_GETPUBKEY,"Retrieve public key for user %s\n"),glocal.user.c_str()); return 0; glocal string pubkey; if (!remote_user && ctx.is_internal()){ (ctx.con,nickname); if (success){ glocal.pubkey = pubkey; } glocal.c->ok(internal_error,success,pubkey); }else{ (hcon,local_user); if (success){ glocal.pubkey = pubkey; } glocal.c->ok(internal_error,success,pubkey); } if (glocal.pubkey.size() > 0){ pubkeys[glocal.user] = glocal.pubkey; (bofs_pubcachefile(),true); fprintf (fout,"#%s\n%s\n",glocal.user.c_str(),glocal.pubkey.c_str()); return 0; } } } #define _TLMP_bofs_addfile_bob struct _F_bofs_addfile_bob { #define _F_bofs_addfile_bob_ok(x) void x ok(bool internal_error, bool success, const char *msg, const char *handle) virtual _F_bofs_addfile_bob_ok( )=0; }; static void bofs_addfile_bob(_F_bofs_addfile_bob &c, CONTEXT &ctx, PARAM_STRING path, const BOB_TYPE &content, bool more) { glocal _F_bofs_addfile_bob *c = &c; if (ctx.is_internal()){ (ctx.con,ctx.sessionid,path,content,more); glocal.c->ok(internal_error,success,msg,handle); }else{ (ctx.hcon,ctx.hsessionid,path,content,more); glocal.c->ok(internal_error,success,msg,handle); } } #define _TLMP_bofs_modifyfile_bob struct _F_bofs_modifyfile_bob { #define _F_bofs_modifyfile_bob_ok(x) void x ok(bool internal_error, bool success, const char *msg, const char *handle) virtual _F_bofs_modifyfile_bob_ok( )=0; }; static void bofs_modifyfile_bob(_F_bofs_modifyfile_bob &c, CONTEXT &ctx, PARAM_STRING path, const BOB_TYPE &content, bool more) { glocal _F_bofs_modifyfile_bob *c = &c; if (ctx.is_internal()){ (ctx.con,ctx.sessionid,path,content,more); glocal.c->ok(internal_error,success,msg,handle); }else{ (ctx.hcon,ctx.hsessionid,path,content,more); glocal.c->ok(internal_error,success,msg,handle); } } #define _TLMP_bofs_split struct _F_bofs_split { #define _F_bofs_split_bo_file(x) int x bo_file(CONTEXT &ctx, const char *path) virtual _F_bofs_split_bo_file( ); #define _F_bofs_split_https_file(x) int x https_file(CONTEXT &ctx, const char *path, const char *host, const char *port, bool use_ssl) virtual _F_bofs_split_https_file( ); #define _F_bofs_split_local_file(x) int x local_file(const char *path) virtual _F_bofs_split_local_file( ); }; int _F_bofs_split::bo_file(CONTEXT &ctx, const char *path) { tlmp_error (MSG_U(E_BOFILENOTDOE,"Bolixo file %s not processed\n"),path); return -1; } int _F_bofs_split::https_file(CONTEXT &ctx, const char *path, const char *host, const char *port, bool use_ssl) { tlmp_error (MSG_U(E_HTTPFILENOTDONE,"Https file %s not processed\n"),path); return -1; } int _F_bofs_split::local_file(const char *path) { tlmp_error (MSG_U(E_LOCALFILENOTDONE,"Local file %s not processed\n"),path); return -1; } static int bofs_splithttp (const char *line, string &host, string &port, string &path) { int ret = -1; // Line starts after the // const char *pt = strchr(line,'/'); if (pt != NULL){ ret = 0; path = pt; host = string(line,pt-line); }else{ host = line; ret = 0; } auto pos = host.find(':'); if (pos != string::npos){ port = host.substr(pos+1); host = host.substr(0,pos); } return ret; } static int bofs_split_http (CONTEXT &ctx, const char *arg, string &host, string &port, string &path) { int ret = -1; if (strncmp(arg,"https://",8)==0){ if (bofs_splithttp(arg+8,host,port,path)==-1){ ret = -1; }else{ ctx.hcon.host = host; ctx.hcon.port = port; ctx.hcon.use_ssl = true; ret = 0; } }else if (strncmp(arg,"http://",7)==0){ if (bofs_splithttp(arg+7,host,port,path)==-1){ ret = -1; }else{ ctx.hcon.host = host; ctx.hcon.port = port; ctx.hcon.use_ssl = false; ret = 0; } } return ret; } static int bofs_split (_F_bofs_split &c, CONTEXT &ctx, int argc, char *argv[]) { int ret = 0; for (int i=0; ret == 0 && i static int bofs_stat ( CONTEXT &ctx, PARAM_STRING _path, string &parent, FILEINFO &file) { glocal int ret = 0; glocal FILEINFO *file = &file; const char *path = _path.ptr; parent.clear(); file.clear(); if (path[0] != '/'){ tlmp_error (MSG_U(E_IVLDPATH,"bofs_stat: Invalid path %s\n"),path); glocal.ret = -1; }else if (strcmp(path,"/")==0){ file.type = ENTRY_DIR; }else{ string dir; string filename; const char *pt = strrchr(path,'/'); if (pt == path){ dir = "/"; filename = path+1; }else{ dir = string (path,pt-path); filename = pt+1; } parent = dir; file.name = filename; //tlmp_error ("bofs_stat: path=%s\n",path); glocal.ret = -1; if (!ctx.is_internal()){ (ctx.hcon,ctx.hsessionid,path,ctx.threshold); if (success){ glocal.ret = 0; (*glocal.file) = file; }else{ // A missing file is not an error. // bofs_error ("stat",internal_error,"Can't stat bolixo file %s: %s",glocal.file->name.c_str(),msg); } }else{ (ctx.con,ctx.sessionid,path,ctx.threshold); if (success){ glocal.ret = 0; (*glocal.file) = file; }else{ // A missing file is not an error. // bofs_error ("stat",internal_error,"Can't stat bolixo file %s: %s",glocal.file->name.c_str(),msg); } } } return glocal.ret; } static int bofs_stat ( CONTEXT &ctx, PARAM_STRING _path, ENTRY_TYPE &type) { FILEINFO file; string parent; int ret = bofs_stat (ctx,_path,parent,file); type = file.type; return ret; } static void bofs_printdir (bool opt_long, const vector &files, bool nostatus) { if (opt_long){ unsigned max_owner = 0; unsigned max_members = 0; unsigned max_modes = 0; unsigned max_size = 0; unsigned max_name = 0; unsigned max_viewed = 0; for (auto s:tbviewed){ unsigned len = strlen(s->get()); if (len > max_viewed) max_viewed = len; } for (int r=0; r<2; r++){ for (auto &f:files){ string owner; if (f.modifiedby[0] != '\0'){ owner = string_f("%s->%s",f.owner,f.modifiedby); }else{ owner = f.owner; } bofs_maxlen (owner,max_owner); bofs_maxlen (f.listname,max_members); bofs_maxlen (f.listmode,max_modes); const char *name = f.name; string tmpname; if (strlen(name)==21){ tmpname = normalize_uuid(name); name = tmpname.c_str(); } bofs_maxlen (name,max_name); string tmp = string_f ("%u",f.size); if (tmp.size() > max_size) max_size = tmp.size(); if (r==1){ const char *listmode = f.listmode; if (listmode[0] == '\0') listmode = " "; string member_mode = string_f("%s:%s",f.listname,f.listmode); fputc('\t',stdout); if (!nostatus){ printf ("%-*s ",max_viewed,tbviewed[f.viewed]->get()); } printf ("%c%-3s %s %s %*s/%-*s %*u %-*s %s\n" ,tbtype[f.type],tbftype[f.file_type] ,normalize_date(f.eventdate),normalize_date(f.modified) ,max_owner,owner.c_str() ,max_members+max_modes+1,member_mode.c_str(),max_size,normalize_size(f.size) ,max_name,name,f.title); } } } }else{ for (auto &e:files) printf ("%s\n",e.name); } } static int bofs_printonefile (CONTEXT &ctx, bool opt_long, const char *path) { int ret = 0; FILEINFO file; string parent; if (bofs_stat(ctx,path,parent,file)==-1){ bofs_error ("ls",false,MSG_U(E_STAT,"Can't stat file %s"),path); ret = -1; }else{ if (opt_long){ printf ("\t%s %c%s %s %s %s/%s:%s %u %s %s\n" ,tbviewed[file.viewed]->get() ,tbtype[file.type],tbftype[file.file_type] ,normalize_date(file.eventdate),normalize_date(file.modified) ,file.owner.c_str(),file.listname.c_str(),file.listmode.c_str() ,normalize_size(file.size),file.name.c_str(),file.title.c_str()); }else{ printf ("%s\n",file.name.c_str()); } } return ret; } static int bofs_ls (CONTEXT &ctx, int argc, char *argv[]) { glocal int ret = -1; glocal bool opt_long = false; glocal bool opt_history = false; glocal CONTEXT *ctx = &ctx; glocal const char *threshold = NULL; glocal bool nostatus = false; glocal.ret = (argc,argv); setproginfo ("bols",VERSION ,"Command line tool to list bolixo content\n" "\n" "bofs ls ...\n" ); setarg ('h',"history","Show all versions of files and sub-directories",glocal.opt_history,false); setarg ('l',"long","Long listing",glocal.opt_long,false); setarg ('t',"threshold","Date threshold, only older-or-equal entries are shown/used (aaaa/mm/jj-hh:mm:ss)",glocal.threshold,false); setarg (' ',"nostatus","Do not display the status of a file (new,modified)",glocal.nostatus,false); int ret = 0; if (glocal.threshold != NULL) glocal.ctx->threshold = glocal.threshold; ret = (*glocal.ctx,argc,argv); glocal int ret = 0; glocal const char *path = path; glocal bool stop = false; unsigned offset = 0; while (!glocal.stop){ (ctx.con,ctx.sessionid,path,ctx.threshold,glocal.opt_history,offset,500); if (!success){ if (internal_error){ bofs_error ("ls",true,"Can't list directory"); }else{ // Maybe glocal.path is a file, so listdir failed //tlmp_error ("listdir %d %s\n",success,msg); glocal.ret = bofs_printonefile(*glocal.ctx,glocal.opt_long,glocal.path); } glocal.stop = true; }else{ bofs_printdir (glocal.opt_long,files,glocal.nostatus); glocal.stop = files.size() < 500; } offset += 500; } return glocal.ret; glocal int ret = 0; glocal const char *path = path; glocal bool stop = false; glocal unsigned chunk = 200; unsigned offset = 0; while (!glocal.stop){ (ctx.hcon,ctx.hsessionid,path,ctx.threshold,glocal.opt_history,offset,glocal.chunk); if (!success){ if (internal_error){ bofs_error ("ls",true,"webapi can't list directory"); }else{ glocal.ret = bofs_printonefile(*glocal.ctx,glocal.opt_long,glocal.path); } glocal.stop = true; }else{ bofs_printdir (glocal.opt_long,files,glocal.nostatus); glocal.stop = files.size() < glocal.chunk; } offset += glocal.chunk; } return glocal.ret; return system (string_f("ls %s %s",glocal.opt_long ? "-l" : "",path).c_str()); return ret; return glocal.ret; } static int bofs_cat_rest (CONTEXT &ctx, const char *handle, FILE *fin) { glocal int ret = 0; bool more = true; while (more && glocal.ret == 0){ char buf[REQ_CONTENT_CHUNK]; auto len = fread (buf,1,sizeof(buf),fin); more = len == sizeof(buf); if (!ctx.is_internal()){ (ctx.hcon,ctx.hsessionid,handle,BOB_TYPE(buf,len,false),more); if (!success){ bofs_error ("cat_rest http",internal_error,msg); glocal.ret = -1; } }else{ (ctx.con,ctx.sessionid,handle,BOB_TYPE(buf,len,false),more); if (!success){ bofs_error ("cat_rest internal",internal_error,msg); glocal.ret = -1; } } } return glocal.ret; } static void bofs_checksig(CONTEXT &ctx, const BOB_TYPE &content, PARAM_STRING path, PARAM_STRING owner, PARAM_STRING modifiedby, PARAM_STRING signature) { glocal string pubkey; glocal const char *owner = owner.ptr; if (modifiedby.ptr[0] != '\0') glocal.owner = modifiedby.ptr; (ctx,glocal.owner); if (!success){ tlmp_error (MSG_U(E_CANTGETOWNERPUBKEY,"Can't get public key for user %s\n"),glocal.owner); }else{ glocal.pubkey = pubkey; } debug_printf (D_SIGN,"user %s->%s public key = %s\n",owner.ptr,modifiedby.ptr,glocal.pubkey.c_str()); if (glocal.pubkey.size() > 0){ if (fs_verify (glocal.pubkey,content,signature)==-1){ tlmp_error (MSG_U(E_FILESIGNOMATCH,"Signature does not match for file %s, author %s\n") ,path.ptr,glocal.owner); }else{ debug_printf (D_SIGN,"File %s, signature valid\n",path.ptr); } } } static void bofs_checksig(CONTEXT &ctx, PARAM_STRING content, PARAM_STRING path, PARAM_STRING owner, PARAM_STRING modifiedby, PARAM_STRING signature) { bofs_checksig(ctx,BOB_TYPE(content.ptr,strlen(content.ptr),false),path,owner,modifiedby,signature); } static int bofs_cat_bofile (CONTEXT &ctx, const char *path, FILE *fout) { glocal int ret = 0; glocal const char *path = path; glocal FILE *fout = fout; glocal CONTEXT *ctx = &ctx; (ctx,path,ctx.threshold,false); if (!success){ bofs_error ("cat",internal_error,msg); glocal.ret = -1; }else{ if (info.signature[0] == '\0'){ tlmp_error (MSG_U(E_NOSIGFORFILE,"No signature for file %s, owner %s\n") ,glocal.path,info.owner); }else if (!more){ bofs_checksig(*glocal.ctx,content,glocal.path,info.owner,info.modifiedby,info.signature); } fwrite (content.getbuffer(),1,content.getsize(),glocal.fout); glocal bool more = more; while (glocal.more){ (*glocal.ctx,handle); fwrite (content.getbuffer(),1,content.getsize(),glocal.fout); glocal.more = more; } } return glocal.ret; } static int bofs_write_bofile(CONTEXT &ctx, PARAM_STRING path, FILE *fin, const char *command) { glocal const char *command = command; glocal int ret = 0; glocal CONTEXT *ctx = &ctx; glocal FILE *fin = fin; string modified; ENTRY_TYPE type; char buf[REQ_CONTENT_CHUNK]; int len = fread (buf,1,sizeof(buf),fin); glocal bool more = len == sizeof(buf); if (bofs_stat(ctx,path,type)==-1){ (ctx,path,BOB_TYPE(buf,len,false),glocal.more); if (!success){ bofs_error (glocal.command,internal_error,msg); glocal.ret = -1; }else if (glocal.more){ glocal.ret = bofs_cat_rest (*glocal.ctx,handle,glocal.fin); } }else if (!bolixo_isfile(type)){ tlmp_error (MSG_U(E_CANTMODIFY,"Can't modify %s, not a file\n"),path.ptr); }else{ (ctx,path,BOB_TYPE(buf,len,false),glocal.more); if (!success){ bofs_error (glocal.command,internal_error,msg); glocal.ret = -1; }else if (glocal.more){ glocal.ret = bofs_cat_rest (*glocal.ctx,handle,glocal.fin); } } return glocal.ret; } static int bofs_cat (CONTEXT &ctx, int argc, char *argv[]) { glocal int ret = -1; glocal CONTEXT *ctx = &ctx; glocal const char *pipeto = NULL; glocal const char *threshold = NULL; glocal.ret = (argc,argv); setproginfo ("bocat",VERSION ,"Command line tool to cat bolixo content\n" "\n" "bofs cat ...\n" ); setarg ('p',"pipeto","Pipe input to this file",glocal.pipeto,false); setarg ('t',"threshold","Date threshold, only older-or-equal entries are shown/used (aaaa/mm/jj-hh:mm:ss)",glocal.threshold,false); int ret = -1; if (glocal.pipeto == NULL){ usage(); }else{ char *argv[1] = {(char*)glocal.pipeto}; ret = (*glocal.ctx,1,argv); return bofs_write_bofile (*glocal.ctx,path,stdin,"cat"); return bofs_write_bofile (*glocal.ctx,path,stdin,"cat"); return system (string_f("cat >%s",path).c_str()); } return ret; int ret = 0; if (glocal.threshold != NULL) glocal.ctx->threshold = glocal.threshold; ret = (*glocal.ctx,argc,argv); return bofs_cat_bofile (ctx,path,stdout); return bofs_cat_bofile (ctx,path,stdout); return system (string_f("cat %s",path).c_str()); return ret; return glocal.ret; } enum BO_SOURCE { BO_ENTRY, HTTPS_ENTRY, LOCAL_ENTRY}; struct BO_ARGTYPE{ string path; string name; BO_SOURCE source; ENTRY_TYPE type; BO_ARGTYPE(PARAM_STRING _path, BO_SOURCE _source, ENTRY_TYPE _type){ path = _path.ptr; const char *pt = strrchr(_path.ptr,'/'); if (pt != NULL){ name = pt+1; }else{ name = path; } source = _source; type = _type; } }; static int bofs_copy_file(CONTEXT &ctx, PARAM_STRING path0, BO_SOURCE src0, PARAM_STRING path1, BO_SOURCE src1) { glocal CONTEXT *ctx = &ctx; glocal int ret = -1; if (src0 == LOCAL_ENTRY){ if (src1 == LOCAL_ENTRY){ // Copying two local files glocal.ret = system (string_f ("cp %s %s",path0.ptr,path1.ptr).c_str()); }else if (is_any_of(src1,BO_ENTRY,HTTPS_ENTRY)){ if (verbose) printf (MSG_R(I_COPY),path0.ptr,path1.ptr); FILE *fin = fopen (path0.ptr,"r"); if (fin == NULL){ bofs_error ("cp",false,"Can't open file %s (%s)",path0.ptr,strerror(errno)); glocal.ret = -1; }else{ glocal.ret = bofs_write_bofile (*glocal.ctx,path1,fin,"cp"); fclose (fin); } } }else if (src0 == BO_ENTRY){ if (src1 == LOCAL_ENTRY){ glocal const char *path0 = path0.ptr; (path1,false); glocal.ret = bofs_cat_bofile (*glocal.ctx,glocal.path0,fout); return 0; }else if (src1 == BO_ENTRY){ (ctx.con,ctx.sessionid,path0,"",path1); if (!success){ glocal.ret = -1; bofs_error ("cp",internal_error,msg); } }else if (src1 == HTTPS_ENTRY){ notdone(); // bolixo 2 bolixo } }else if (src0 == HTTPS_ENTRY){ if (src1 == LOCAL_ENTRY){ glocal const char *path0 = path0.ptr; (path1,false); glocal.ret = bofs_cat_bofile (*glocal.ctx,glocal.path0,fout); return 0; }else if (src1 == BO_ENTRY){ notdone(); // bolixo 2 bolixo }else if (src1 == HTTPS_ENTRY){ notdone(); // bolixo 2 bolixo } } return glocal.ret; } static int bofs_mkdir (CONTEXT &ctx, PARAM_STRING path) { glocal int ret = -1; glocal const char *path = path.ptr; if (ctx.is_internal()){ (ctx.con,ctx.sessionid,path); if (success){ glocal.ret = 0; }else{ bofs_error ("mkdir",internal_error,MSG_U(E_MKDIR,"Can't create directory %s: %s"),glocal.path,msg); } }else{ (ctx.hcon,ctx.hsessionid,path); if (success){ glocal.ret = 0; }else{ bofs_error ("mkdir",internal_error,MSG_R(E_MKDIR),glocal.path,msg); } } return glocal.ret; } static int bofs_copy_dir(CONTEXT &ctx, PARAM_STRING path0, BO_SOURCE src0, PARAM_STRING path1, BO_SOURCE src1) { glocal CONTEXT *ctx = &ctx; glocal int ret = -1; if (src0 == LOCAL_ENTRY){ if (src1 == LOCAL_ENTRY){ // Copying two local directories glocal.ret = system (string_f ("cp -r %s %s %s",verbose ? "-v" : "",path0.ptr,path1.ptr).c_str()); }else if (is_any_of(src1,BO_ENTRY,HTTPS_ENTRY)){ glocal string path1 = path1.ptr; if (bofs_mkdir(ctx,path1)!=-1){ (path0); string dstpath = string_f("%s/%s",glocal.path1.c_str(),relpath); if (is_dir){ if (verbose) printf (MSG_U(I_MKDIR,"mkdir %s\n"),dstpath.c_str()); glocal.ret = bofs_mkdir (*glocal.ctx,dstpath); }else{ FILE *fin = fopen (path,"r"); if (fin == NULL){ bofs_error ("cp",false,MSG_U(E_OPENFILE,"Can't open file %s (%s)"),path,strerror(errno)); glocal.ret = -1; }else{ if (verbose) printf (MSG_U(I_COPY,"copy %s %s\n"),path,dstpath.c_str()); glocal.ret = bofs_write_bofile (*glocal.ctx,dstpath,fin,"cp"); fclose (fin); } } if (glocal.ret == -1) end(); } } }else if (is_any_of(src0,BO_ENTRY,HTTPS_ENTRY)){ if (src1 == LOCAL_ENTRY){ glocal deque todo; glocal.todo.push_back(path0.ptr); glocal.ret = 0; while(glocal.todo.size() > 0 && glocal.ret != -1){ glocal bool stop = false; glocal string dir = glocal.todo.front(); glocal string path1; glocal.todo.pop_front(); // We compute the target directory unsigned len = strlen(path0.ptr); if (glocal.dir.size() > len){ glocal.path1 = string_f("%s/%s",path1.ptr,glocal.dir.c_str()+len+1); }else{ glocal.path1 = path1.ptr; } if (verbose) printf ("mkdir %s\n",glocal.path1.c_str()); if (mkdir (glocal.path1.c_str(),0755)==-1){ tlmp_error (MSG_R(E_MKDIR),path1.ptr,strerror(errno)); glocal.ret = -1; } unsigned offset = 0; while (!glocal.stop && glocal.ret != -1){ (ctx,glocal.dir,"",false,offset,500); for (auto &f:files){ string path = string_f("%s/%s",glocal.dir.c_str(),f.name); if (bolixo_isdir(f.type)){ glocal.todo.push_back(path); }else{ string dst = string_f("%s/%s",glocal.path1.c_str(),f.name); if (verbose) printf ("copy %s -> %s\n",path.c_str(),dst.c_str()); glocal.ret = bofs_copy_file (*glocal.ctx,path,BO_ENTRY,dst,LOCAL_ENTRY); } } glocal.stop = files.size() < 500; offset += 500; } } }else if (src0 == src1 && src1 == BO_ENTRY){ (ctx.con,ctx.sessionid,path0,"",path1); if (!success){ glocal.ret = -1; bofs_error ("cp",internal_error,msg); } }else if (src0 == src1 && src1 == HTTPS_ENTRY){ (ctx.hcon,ctx.hsessionid,path0,"",path1); if (!success){ glocal.ret = -1; bofs_error ("cp",internal_error,msg); } }else if (src1 == HTTPS_ENTRY){ notdone(); // bolixo 2 bolixo } } return glocal.ret; } static int bofs_checkargs (CONTEXT &ctx, int argc, char *argv[], vector &args) { glocal CONTEXT *ctx = &ctx; glocal vector *args = &args; int ret = (ctx,argc,argv); ENTRY_TYPE type; bofs_stat (*glocal.ctx,path,type); glocal.args->push_back(BO_ARGTYPE(path,HTTPS_ENTRY,type)); return 0; ENTRY_TYPE type; bofs_stat (*glocal.ctx,path,type); glocal.args->push_back(BO_ARGTYPE(path,BO_ENTRY,type)); return 0; struct stat64 st; ENTRY_TYPE type = ENTRY_NONE; if (stat64(path,&st)!=-1){ if (S_ISDIR(st.st_mode)){ type = ENTRY_DIR; }else if (S_ISREG(st.st_mode)){ type = ENTRY_FILE; }else{ bofs_error ("cp",false,"Unsupported file type %s",path); exit (-1); } } glocal.args->push_back(BO_ARGTYPE(path,LOCAL_ENTRY,type)); return 0; return ret; } static int bofs_cp (CONTEXT &ctx, int argc, char *argv[]) { glocal int ret = -1; glocal CONTEXT *ctx = &ctx; glocal.ret = (argc,argv); setproginfo ("bocp",VERSION ,MSG_U(I_BOCP,"Command line tool to copy Bolixo content\n" "\n" "bofs cp ...\n") ); setarg ('v',"verbose",MSG_U(I_VERBOSE,"Display files as they are copied"),verbose,false); int ret = 0; vector args; if (bofs_checkargs (*glocal.ctx, argc, argv, args)==-1){ ret = -1; }else{ auto args_size = args.size(); // Check if all the entries prior to the last one exist in the file systems bool missing_one = false; for (unsigned i=0; i return glocal.ret; } static int bofs_rm (CONTEXT &ctx, int argc, char *argv[]) { glocal int ret = -1; glocal CONTEXT *ctx = &ctx; glocal.ret = (argc,argv); setproginfo ("borm",VERSION ,MSG_U(I_BORM ,"Command line tool to erase Bolixo content\n" "\n" "bofs rm ...\n") ); int ret = -1; ret = (*glocal.ctx,argc,argv); glocal int ret = -1; glocal const char *path = path; (ctx.con,ctx.sessionid,path); if (success){ glocal.ret = 0; }else{ bofs_error ("rm",internal_error,MSG_U(E_CANTDELETE,"Can't delete Bolixo file %s: %s"),glocal.path,msg); } return glocal.ret; glocal int ret = -1; glocal const char *path = path; (ctx.hcon,ctx.hsessionid,path); if (success){ glocal.ret = 0; }else{ bofs_error ("rm",internal_error,MSG_R(E_CANTDELETE),glocal.path,msg); } return glocal.ret; return system (string_f("rm %s",path).c_str()); return ret; return glocal.ret; } static int bofs_mv (CONTEXT &ctx, int argc, char *argv[]) { glocal int ret = -1; glocal CONTEXT *ctx = &ctx; glocal.ret = (argc,argv); setproginfo ("bomv",VERSION ,"Command line tool to move/rename bolixo content\n" "\n" "bofs mv ...\n" ); glocal int ret = 0; vector args; if (bofs_checkargs (*glocal.ctx, argc, argv, args)==-1){ glocal.ret = -1; }else{ if (args.size() != 2){ bofs_error ("mv",false,"Accepts only two arguments"); glocal.ret = -1; }else{ BO_SOURCE src0 = args[0].source; if (src0 != args[1].source){ bofs_error ("mv",false,"Can't mv file across different file-systems"); glocal.ret = -1; }else{ const char *path0 = args[0].path.c_str(); const char *path1 = args[1].path.c_str(); if (src0 == LOCAL_ENTRY){ glocal.ret = system (string_f ("mv %s %s",path0,path1).c_str()); }else if (src0 == BO_ENTRY){ (glocal.ctx->con,glocal.ctx->sessionid,path0,path1); if (!success){ glocal.ret = -1; bofs_error ("mv",internal_error,msg); } }else{ glocal.ret = -1; } } } } return glocal.ret; return glocal.ret; } static int bofs_mkdir (CONTEXT &ctx, int argc, char *argv[]) { glocal int ret = -1; glocal CONTEXT *ctx = &ctx; glocal.ret = (argc,argv); setproginfo ("bomkdir",VERSION ,"Command line tool to create Bolixo directory\n" "\n" "bofs mkdir ...\n" ); int ret = -1; ret = (*glocal.ctx,argc,argv); return bofs_mkdir(ctx,path); glocal int ret = -1; glocal const char *path = path; (ctx.hcon,ctx.hsessionid,path); if (success){ glocal.ret = 0; }else{ bofs_error ("mkdir",internal_error,MSG_R(E_MKDIR),glocal.path,msg); } return glocal.ret; return system (string_f("mkdir %s",path).c_str()); return ret; return glocal.ret; } static int bofs_rmdir (CONTEXT &ctx, int argc, char *argv[]) { glocal int ret = -1; glocal CONTEXT *ctx = &ctx; glocal.ret = (argc,argv); setproginfo ("bormdir",VERSION ,"Command line tool to remove Bolixo directory\n" "\n" "bofs ls ...\n" ); int ret = -1; ret = (*glocal.ctx,argc,argv); glocal int ret = -1; glocal const char *path = path; (ctx.con,ctx.sessionid,path); if (success){ glocal.ret = 0; }else{ bofs_error ("rmdir",internal_error,"Can't remove directory %s: %s",glocal.path,msg); } return glocal.ret; glocal int ret = -1; glocal const char *path = path; (ctx.hcon,ctx.hsessionid,path); if (success){ glocal.ret = 0; }else{ bofs_error ("rmdir",internal_error,"Can't remove directory %s: %s",glocal.path,msg); } return glocal.ret; return system (string_f("rmdir %s",path).c_str()); return ret; return glocal.ret; } static int bofs_print_groups (CONTEXT &ctx, const char *owner, const char *onegroup, unsigned indent, bool only_owner) { glocal int ret = -1; glocal unsigned indent = indent; glocal const char *onegroup = onegroup; glocal vector groups; if (ctx.is_internal()){ (ctx.con,ctx.sessionid,owner,only_owner); if (success){ for (auto &g:groups) glocal.groups.push_back(g); }else{ bofs_error ("groups",internal_error,"Can't list groups: %s",msg); } }else{ (ctx.hcon,ctx.hsessionid,owner,only_owner); if (success){ for (auto &g:groups) glocal.groups.push_back(g); }else{ bofs_error ("groups",internal_error,"Can't list groups: %s",msg); } } glocal.ret = 0; unsigned max_owner = 0; unsigned max_groupname = 0; unsigned max_user = 0; for (unsigned r=0; r<2; r++){ for (auto &g:glocal.groups){ const char *groupname = g.name.c_str(); const char *owner = g.owner.c_str(); if (glocal.onegroup != NULL && strcmp(glocal.onegroup,groupname)!=0) continue; bofs_maxlen (owner,max_owner); bofs_maxlen (groupname,max_groupname); const vector &us = g.users; if (us.size() == 0){ if (r > 0) printf ("%-*s %-*s\n",max_owner,owner,max_groupname,groupname); }else{ const vector &as = g.access; const vector &rs = g.roles; for (unsigned j=0; j 0){ if (glocal.onegroup != NULL) groupname = ""; printf ("%*s%-*s %-*s\t%*s\t%s\t%s\n",glocal.indent,"" ,max_owner,owner,max_groupname,groupname,max_user ,us[j].c_str(),as[j].c_str(),rs[j].c_str()); } groupname = ""; owner = ""; } } } } return glocal.ret; } /* Pretty print lists (projects) */ static int bofs_print_lists(CONTEXT &ctx, const char *owner, const vector &lists) { int ret = 0; unsigned max_listname=0; unsigned max_group=0; // 2 passes to compute the maximum field length for (int r=0; r<2; r++){ for (unsigned i=0; i &gs = l.groups; if (gs.size() == 0){ printf ("%s\n",listname); }else{ const vector &as = l.access; for (unsigned j=0; j static int bofs_groups(CONTEXT &ctx, int argc, char *argv[]) { glocal CONTEXT *ctx = &ctx; glocal bool create_group_list = false; glocal bool create_group = false; glocal bool set_group = false; glocal bool set_member = false; glocal bool delete_list = false; glocal bool delete_group = false; glocal bool print_lists = false; glocal bool print_groups = false; glocal bool print_contacts = false; glocal bool set_access = false; glocal bool create_project_dir = false; glocal bool set_group_desc = false; glocal bool set_list_desc = false; glocal const char *description = NULL; glocal const char *filename = NULL; glocal const char *listname = NULL; glocal const char *listmode = " "; glocal const char *groupname = NULL; glocal const char *access = "R"; glocal const char *user = NULL; glocal const char *role = ""; glocal bool only_owner = false; glocal const char *owner = ""; int ret = (argc,argv); setproginfo ("bogroups",VERSION ,"Command line tool to configure bolixo groups and group lists\n" "\n" "bofs groups ...\n" ); setgrouparg ("Commands"); setarg ('g',"create-group","Create a group of users",glocal.create_group,false); setarg ('l',"create-group-list","Create a list of groups",glocal.create_group_list,false); setarg (' ',"set-list-desc","Set list description",glocal.set_list_desc,false); setarg (' ',"set-group-desc","Set group description",glocal.set_group_desc,false); setarg ('s',"set-group","Configure a group as a member of a list",glocal.set_group,false); setarg ('m',"set-member","Configure a user a a member of a group",glocal.set_member,false); setarg ('d',"create-project-dir","Create the project directory for a list",glocal.create_project_dir,false); setgrouparg ("Deletion"); setarg (' ',"delete-list","Delete one list",glocal.delete_list,false); setarg (' ',"delete-group","Delete one group",glocal.delete_group,false); setgrouparg ("Print"); setarg (' ',"print-contacts",MSG_U(O_PRINTCONTACTS,"Print members of the contacts group"),glocal.print_contacts,false); setarg (' ',"print-lists",MSG_U(O_PRINTLISTS,"Print the content of a lists/projects"),glocal.print_lists,false); setarg (' ',"print-groups",MSG_U(O_PRINTGROUPS,"Print the content of groups"),glocal.print_groups,false); setgrouparg ("Access"); setarg ('a',"set-access","Assign a user/list name to a file or directory",glocal.set_access,false); setarg ('M',"listmode","list mode override (' ','p','r','w','a')",glocal.listmode,false); setgrouparg ("Arguments"); setarg ('D',"description","Description for set-group-desc and set-list-desc",glocal.description,false); setarg ('P',"filename","File or directory path",glocal.filename,false); setarg ('L',"listname","List name",glocal.listname,false); setarg ('G',"groupname","Group name",glocal.groupname,false); setarg ('U',"user","User/member of a group",glocal.user,false); setarg ('A',"access","Access or default access",glocal.access,false); setarg ('R',"role","(for set-member) Activity of this member",glocal.role,false); setarg ('O',"owner",MSG_R(O_OWNER),glocal.owner,false); setarg (' ',"only_owner","Shows only groups owned by this user (--print-groups)",glocal.only_owner,false); glocal int ret = -1; if (glocal.ctx->login()==-1){ }else if (glocal.create_group_list){ if (glocal.listname == NULL){ bofs_error ("groups",false,"You must specify the list name"); }else if (glocal.ctx->is_internal()){ (glocal.ctx->con,glocal.ctx->sessionid,glocal.listname,glocal.owner); if (success){ glocal.ret = 0; }else{ bofs_error ("groups",internal_error, "Can't create group_list: %s",msg); } }else{ notdone(); // create_group_list } }else if (glocal.create_group){ if (glocal.groupname == NULL){ bofs_error ("groups",false,"You must specify the group name"); }else if (glocal.ctx->is_internal()){ (glocal.ctx->con,glocal.ctx->sessionid,glocal.groupname,glocal.owner); if (success){ glocal.ret = 0; }else{ bofs_error ("groups",internal_error,"Can't create group: %s",msg); } }else{ notdone(); // create_group } }else if (glocal.set_list_desc){ if (glocal.listname == NULL){ bofs_error ("groups",false,"You must specify the list name"); }else if (glocal.description == NULL){ bofs_error ("groups",false,"You must specify the description"); }else if (glocal.ctx->is_internal()){ (glocal.ctx->con,glocal.ctx->sessionid,glocal.listname,glocal.description,glocal.owner); if (success){ glocal.ret = 0; }else{ bofs_error ("groups",internal_error,"Can't set list description: %s",msg); } }else{ notdone(); // set_list_desc } }else if (glocal.set_group_desc){ if (glocal.groupname == NULL){ bofs_error ("groups",false,"You must specify the group name"); }else if (glocal.description == NULL){ bofs_error ("groups",false,"You must specify the description"); }else if (glocal.ctx->is_internal()){ (glocal.ctx->con,glocal.ctx->sessionid,glocal.groupname,glocal.description,glocal.owner); if (success){ glocal.ret = 0; }else{ bofs_error ("groups",internal_error,"Can't set group description: %s",msg); } }else{ notdone(); // set_group_desc } }else if (glocal.set_group){ if (glocal.listname == NULL){ bofs_error ("groups",false,"You must specify the list name"); }else if (glocal.groupname == NULL){ bofs_error ("groups",false,"You must specify the group name"); }else if (glocal.ctx->is_internal()){ (glocal.ctx->con,glocal.ctx->sessionid,glocal.listname,glocal.groupname,glocal.access,glocal.owner); if (success){ glocal.ret = 0; }else{ bofs_error ("groups",internal_error,"Can't assign group to a list: %s",msg); } }else{ notdone(); // set_group } }else if (glocal.set_member){ if (glocal.groupname == NULL){ bofs_error ("groups",false,"You must specify the group name"); }else if (glocal.ctx->is_internal()){ (glocal.ctx->con,glocal.ctx->sessionid,glocal.groupname,glocal.user,glocal.access,glocal.role,glocal.owner); if (success){ glocal.ret = 0; }else{ bofs_error ("groups",internal_error,"Can't assign user to a group: %s",msg); } }else{ notdone(); // set_member } }else if (glocal.create_project_dir){ if (glocal.listname == NULL){ bofs_error ("groups",false,"You must specify the list name"); }else if (glocal.ctx->is_internal()){ (glocal.ctx->con,glocal.ctx->sessionid,glocal.listname,glocal.owner); if (success){ glocal.ret = 0; }else{ bofs_error ("groups",internal_error,"Can't create project directory: %s\n",msg); } }else{ notdone(); // create_project_dir } }else if (glocal.delete_list){ if (glocal.listname == NULL){ bofs_error ("groups",false,"You must specify the list name"); }else if (glocal.ctx->is_internal()){ (glocal.ctx->con,glocal.ctx->sessionid,glocal.listname,glocal.owner); if (success){ glocal.ret = 0; }else{ bofs_error ("groups",internal_error,"Can't delete the list: %s",msg); } }else{ notdone(); // delete_list } }else if (glocal.delete_group){ if (glocal.groupname == NULL){ bofs_error ("groups",false,"You must specify the group name"); }else if (glocal.ctx->is_internal()){ (glocal.ctx->con,glocal.ctx->sessionid,glocal.groupname,glocal.owner); if (success){ glocal.ret = 0; }else{ bofs_error ("groups",internal_error,"Can't delete the group: %s",msg); } }else{ notdone(); // delete_group } }else if (glocal.print_lists){ if (glocal.ctx->is_internal()){ (glocal.ctx->con,glocal.ctx->sessionid,glocal.owner); if (success){ glocal.ret = bofs_print_lists(*glocal.ctx,glocal.owner,lists); }else{ bofs_error ("groups",internal_error,"Can't list lists: %s",msg); } }else{ (glocal.ctx->hcon,glocal.ctx->hsessionid,glocal.owner); if (success){ glocal.ret = bofs_print_lists(*glocal.ctx,glocal.owner,lists); }else{ bofs_error ("groups",internal_error,"Can't list lists: %s",msg); } } }else if (glocal.print_groups){ glocal.ret = bofs_print_groups (*glocal.ctx,glocal.owner,NULL,0,glocal.only_owner); }else if (glocal.print_contacts){ if (glocal.ctx->is_internal()){ (glocal.ctx->con,glocal.ctx->sessionid,glocal.owner); if (success){ for (auto s:members) printf ("%s\n",s); }else{ bofs_error ("list_contacts",internal_error,"Can't list contacts: %s",msg); } }else{ (glocal.ctx->hcon,glocal.ctx->hsessionid,glocal.owner); if (success){ for (auto s:members) printf ("%s\n",s); }else{ bofs_error ("list_contacts",internal_error,"Can't list contacts: %s",msg); } } }else{ tlmp_error ("One of the following option must be used:\n" "\t--create-group-list\n" "\t--creat-group\n" "\t--set_group\n" "\t--set_member\n" "\n" "\t--delete-list\n" "\t--delete-group\n" "\n" "\t--print-list\n" "\t--print-group\n" ); usage(); } return glocal.ret; glocal int ret = -1; if (glocal.set_access){ if (glocal.ctx->login()!=-1){ const char *username = glocal.user == NULL ? "" : glocal.user; const char *listname = glocal.listname == NULL ? "" : glocal.listname; for (int i=0; i(glocal.ctx->con,glocal.ctx->sessionid,argv[i],username,listname,glocal.listmode); if (!success){ bofs_error ("groups",internal_error,"bofs groups: %s",msg); }else{ glocal.ret = 0; } if (glocal.ret != 0) break; } } }else{ usage(); } return glocal.ret; return ret; } static int bofs_send_talk ( CONTEXT &ctx, const char *textcontent, const char *filecontent, const char *owner, const vector &users, const char *groupname, const char *groupowner) { glocal CONTEXT *ctx = &ctx; glocal int ret = -1; glocal FILE *fcontent = NULL; bool more = false; BOB_TYPE content; char buf[REQ_CONTENT_CHUNK]; if (groupname == NULL) groupname = ""; if (groupowner == NULL) groupowner = ""; if (textcontent != NULL){ content.setbuffer (textcontent,strlen(textcontent),false); }else if (filecontent != NULL){ glocal.fcontent = fopen (filecontent,"r"); if (glocal.fcontent == NULL){ tlmp_error (MSG_U(E_FILECONTENT,"msgs: Can't open filecontent %s (%s)\n"),filecontent,strerror(errno)); }else{ auto nb = fread (buf,1,sizeof(buf),glocal.fcontent); content.setbuffer (buf,nb,false); if (nb == sizeof(buf)) more = true; } }else{ tlmp_error (MSG_U(E_CONTENT,"You must specify either --content or --filecontent option\n")); } if (content.getsize() > 0){ if (ctx.is_internal()){ if (strcmp(groupname,"anonymous")==0){ (ctx.con,ctx.sessionid,groupowner,content,more); if (!success){ bofs_error ("msgs",internal_error,msg); }else{ if (handle[0] != '\0'){ glocal.ret = bofs_cat_rest (*glocal.ctx, handle, glocal.fcontent); }else{ glocal.ret = 0; } } }else{ (ctx.con,ctx.sessionid,owner,users,groupname,groupowner,content,more,"","",""); if (!success){ bofs_error ("msgs",internal_error,msg); }else{ if (handle[0] != '\0'){ glocal.ret = bofs_cat_rest (*glocal.ctx, handle, glocal.fcontent); }else{ glocal.ret = 0; } } } }else{ (ctx.hcon,ctx.hsessionid,owner,users,groupname,groupowner,content,more,"","",""); if (!success){ bofs_error ("msgs",internal_error,msg); }else{ if (handle[0] != '\0'){ glocal.ret = bofs_cat_rest (*glocal.ctx, handle, glocal.fcontent); }else{ glocal.ret = 0; } } } } if (glocal.fcontent != NULL) fclose (glocal.fcontent); return glocal.ret; } static int bofs_send_talk_file ( CONTEXT &ctx, const char *filename, const char *filedate, const char *owner, const vector &users, const char *groupname, const char *groupowner) { glocal int ret = -1; if (groupname == NULL){ tlmp_error ("groupname required for talkmsg\n"); }else{ if (ctx.is_internal()){ (ctx.con,ctx.sessionid,owner,users,groupname,groupowner,filename,filedate); if (!success){ bofs_error ("msgs",internal_error,msg); }else{ glocal.ret = 0; } }else{ (ctx.hcon,ctx.hsessionid,owner,users,groupname,groupowner,filename,filedate); if (!success){ bofs_error ("msgs",internal_error,msg); }else{ glocal.ret = 0; } } } return glocal.ret; } #define _TLMP_bofs_list_msgs struct _F_bofs_list_msgs { #define _F_bofs_list_msgs_ok(x) void x ok(bool internal_error, bool success, const char *msg, const vector &messages) virtual _F_bofs_list_msgs_ok( )=0; }; static void bofs_list_msgs(_F_bofs_list_msgs &c, CONTEXT &ctx, const char *owner, bool deleted, unsigned offset, unsigned chunk) { glocal _F_bofs_list_msgs *c = &c; if (ctx.is_internal()){ (ctx.con,ctx.sessionid,owner,"",deleted,offset,chunk); glocal.c->ok(internal_error,success,msg,messages); }else{ (ctx.hcon,ctx.hsessionid,owner,"",deleted,offset,chunk); glocal.c->ok(internal_error,success,msg,messages); } } #define _TLMP_bofs_list_talk struct _F_bofs_list_talk { #define _F_bofs_list_talk_ok(x) void x ok(bool internal_error, bool success, const char *msg, const vector &messages, bool deletes, unsigned total, unsigned nbnew) virtual _F_bofs_list_talk_ok( )=0; }; static void bofs_list_talk( _F_bofs_list_talk &c, CONTEXT &ctx, const char *owner, const char *groupname, const char *groupowner, unsigned offset, unsigned chunk, const char *firstseen) { glocal _F_bofs_list_talk *c = &c; if (ctx.is_internal()){ (ctx.con,ctx.sessionid,owner,groupname,groupowner,offset,chunk,firstseen); glocal.c->ok(internal_error,success,msg,messages,deletes,total,nbnew); }else{ (ctx.hcon,ctx.hsessionid,owner,groupname,groupowner,offset,chunk,firstseen); glocal.c->ok(internal_error,success,msg,messages,deletes,total,nbnew); } } #define _TLMP_bofs_list_inboxes struct _F_bofs_list_inboxes { #define _F_bofs_list_inboxes_ok(x) void x ok(bool internal_error, bool success, const char *msg, const vector &inboxes) virtual _F_bofs_list_inboxes_ok( )=0; }; static void bofs_list_inboxes (_F_bofs_list_inboxes &c, CONTEXT &ctx, const char *owner) { glocal _F_bofs_list_inboxes *c = &c; if (ctx.is_internal()){ (ctx.con,ctx.sessionid,owner,true); glocal.c->ok(internal_error,success,msg,inboxes); }else{ (ctx.hcon,ctx.hsessionid,owner,true); glocal.c->ok(internal_error,success,msg,inboxes); } } #define _TLMP_bofs_sendmsg struct _F_bofs_sendmsg { #define _F_bofs_sendmsg_ok(x) void x ok(bool internal_error, bool success, const char *msg, const char *msgid) virtual _F_bofs_sendmsg_ok( )=0; }; static void bofs_sendmsg (_F_bofs_sendmsg &c, CONTEXT &ctx, const char *owner, const vector &recipients, const char *title, const char *content) { glocal _F_bofs_sendmsg *c = &c; if (ctx.is_internal()){ (ctx.con,ctx.sessionid,owner,recipients,title,content); glocal.c->ok(internal_error,success,msg,msgid); }else{ (ctx.hcon,ctx.hsessionid,owner,recipients,title,content); glocal.c->ok(internal_error,success,msg,msgid); } } #define _TLMP_bofs_sendmsg_project struct _F_bofs_sendmsg_project { #define _F_bofs_sendmsg_project_ok(x) void x ok(bool internal_error, bool success, const char *msg, const char *msgid) virtual _F_bofs_sendmsg_project_ok( )=0; }; static void bofs_sendmsg_project ( _F_bofs_sendmsg_project &c, CONTEXT &ctx, const char *owner, const char *manager, const char *project, const char *role, const char *title, const char *content) { glocal _F_bofs_sendmsg_project *c = &c; if (ctx.is_internal()){ (ctx.con,ctx.sessionid,owner ,manager,project,role,title,content); glocal.c->ok (internal_error,success,msg,msgid); }else{ (ctx.hcon,ctx.hsessionid,owner ,manager,project,role,title,content); glocal.c->ok (internal_error,success,msg,msgid); } } #define _TLMP_bofs_replymsg struct _F_bofs_replymsg { #define _F_bofs_replymsg_ok(x) void x ok(bool internal_error, bool success, const char *msg, const char *replyid) virtual _F_bofs_replymsg_ok( )=0; }; static void bofs_replymsg ( _F_bofs_replymsg &c, CONTEXT &ctx, const char *owner, const char *msgid, const vector &recipients, const char *title, const char *content) { glocal _F_bofs_replymsg *c = &c; if (ctx.is_internal()){ (ctx.con,ctx.sessionid,owner ,msgid,recipients,title,content); glocal.c->ok (internal_error,success,msg,replyid); }else{ (ctx.hcon,ctx.hsessionid,owner ,msgid,recipients,title,content); glocal.c->ok (internal_error,success,msg,replyid); } } #define _TLMP_bofs_replymsg_project struct _F_bofs_replymsg_project { #define _F_bofs_replymsg_project_ok(x) void x ok(bool internal_error, bool success, const char *msg, const char *replyid) virtual _F_bofs_replymsg_project_ok( )=0; }; static void bofs_replymsg_project ( _F_bofs_replymsg_project &c, CONTEXT &ctx, const char *owner, const char *manager, const char *project, const char *role, const char *msgid, const char *title, const char *content) { glocal _F_bofs_replymsg_project *c = &c; if (ctx.is_internal()){ (ctx.con,ctx.sessionid,owner ,manager,project,role,msgid,title,content); glocal.c->ok (internal_error,success,msg,replyid); }else{ (ctx.hcon,ctx.hsessionid,owner ,manager,project,role,msgid,title,content); glocal.c->ok (internal_error,success,msg,replyid); } } static void bofs_check_groupopt (const char *groupname, const char *groupowner) { if (groupowner == NULL){ tlmp_error (MSG_U(E_GROUPOWNER,"You must specified the group owner (option --groupowner)\n")); exit (-1); }else if (groupname == NULL){ tlmp_error (MSG_U(E_GROUPNAME,"You must specify the group name (option --groupname)\n")); exit (-1); } } static void bofs_check_groupopt (const vector &users, const char *groupname, const char *groupowner) { if (groupname == NULL){ if (users.size() == 0){ tlmp_error (MSG_U(E_NOGROUPORUSERS,"You must specify either a group name (option --groupname) or some user (option --user)\n")); exit (-1); } }else if (groupowner == NULL){ tlmp_error (MSG_R(E_GROUPOWNER)); exit (-1); } } static void bofs_listshortmsgs(CONTEXT &ctx, const vector &messages, bool full) { for (auto &m:messages){ vector lines; bool complete = false; if (m.content[0] != '\0'){ const char *start = m.content; while (*start != '\0'){ const char *eol = strchr(start,'\n'); if (eol == NULL){ lines.push_back(start); break; }else{ lines.push_back(string(start,eol-start)); start = eol+1; } } complete = strlen(m.content)==m.size; if (complete){ bofs_checksig(ctx,m.content,m.uuid,m.from,"",m.signature); } } if (lines.size() == 0) lines.push_back(""); printf ("%s %-10s %-30s %-20s %7u %s\n",tbftype[m.file_type],m.from ,normalize_uuid(m.uuid).c_str() ,normalize_date(m.submit),normalize_size(m.size) ,lines[0].c_str()); if (full){ for (unsigned i=1; i &messages, vector ©) { for (auto &m:messages) copy.push_back(m); if (testmode){ sort (copy.begin(),copy.end() ,[](const SHORTMSG_receive &a, const SHORTMSG_receive &b) -> bool { return strcmp(a.content,b.content)<0; }); } } static int bofs_msgs (CONTEXT &ctx, int argc, char *argv[]) { glocal int ret = -1; glocal CONTEXT *ctx = &ctx; glocal const char *owner = ""; glocal bool list = false; glocal bool attach = false; glocal bool newmsg = false; glocal bool reply = false; glocal bool listmsgs = false; glocal bool shortmsg = false; glocal bool shortmsg_file = false; glocal bool listshortmsgs = false; glocal vector recipients; glocal const char *groupname = NULL; glocal const char *groupowner = NULL; glocal const char *filecontent = NULL; glocal const char *filename = NULL; glocal const char *manager = NULL; glocal const char *project = NULL; glocal const char *role = ""; glocal const char *title = ""; glocal const char *content = NULL; glocal const char *msgid = NULL; glocal const char *firstseen = ""; glocal bool full = false; glocal.ret = (argc,argv); setproginfo ("bomsgs",VERSION ,"Command line tool to access messages\n" "\n" "bofs msgs ...\n" ); setgrouparg ("Main commands"); setarg ('a',"attach",MSG_U(O_ADDATTACH,"Add an attachment to previously sent message"),glocal.attach,false); setarg ('l',"list",MSG_U(O_LISTINBOXES,"List inboxes"),glocal.list,false); setarg ('i',"listmsgs",MSG_U(O_LISTALLINBOXES,"List messages in all inboxes"),glocal.listmsgs,false); setarg ('n',"newmsg",MSG_U(O_SENDMSG,"Send a message"),glocal.newmsg,false); setarg ('r',"reply",MSG_U(O_REPLYMSG,"Reply to a message"),glocal.reply,false); setarg ('t',"shortmsg",MSG_U(O_SENDSHORTMSG,"Send a short message to a group"),glocal.shortmsg,false); setarg ('f',"shortmsg_file",MSG_U(O_SENDFILE,"Send a Bolixo file to a group"),glocal.shortmsg_file,false); setarg ('s',"listshortmsgs",MSG_U(O_LISTSHORTMSGS,"List short messages"),glocal.listshortmsgs,false); setgrouparg ("Options"); setarg ('G',"groupname",MSG_U(O_GROUPNAME,"Group name for short message"),glocal.groupname,false); setarg (' ',"groupowner",MSG_U(O_GROUPOWNER,"Group owner"),glocal.groupowner,false); setarg ('M',"manager",MSG_U(O_MANAGER,"Manager or owner of the inbox"),glocal.manager,false); setarg ('P',"project",MSG_U(O_TARGETINBOX,"Target inbox or project"),glocal.project,false); setarg ('R',"role",MSG_U(O_TARGETROLE,"Target role"),glocal.role,false); setarg ('D',"recipient",MSG_U(O_RECIPIENT,"Recipient of the message"),glocal.recipients,false); setarg ('F',"filecontent",MSG_U(O_FILEMSG,"File holding a message content"),glocal.filecontent,false); setarg ('I',"msgid",MSG_U(O_MSGID,"Message ID we are replying to"),glocal.msgid,false); setarg ('T',"title",MSG_U(O_TITLE,"Title of the message"),glocal.title,false); setarg ('C',"content",MSG_U(O_BODY,"body of the message"),glocal.content,false); setarg ('L',"bolixofile",MSG_U(O_BOFILEPATH,"Bolixo file path"),glocal.filename,false); setarg (' ',"firstseen",MSG_U(O_FIRSTSEEN,"First visible message"),glocal.firstseen,false); setgrouparg (MSG_R(I_MISC)); setarg ('O',"owner",MSG_U(O_OWNER,"Apply the command on behalf of this owner, must be admin"),glocal.owner,false); setarg (' ',"full",MSG_U(O_FULL,"Display the full content of small messages"),glocal.full,false); glocal int ret = -1; if (glocal.groupowner == NULL){ glocal.groupowner = glocal.ctx->user.c_str(); const char *pt = strchr(glocal.groupowner,'/'); if (pt != NULL) glocal.groupowner = pt+1; } if (glocal.listmsgs){ glocal bool stop = false; glocal unsigned offset=0; glocal unsigned chunk=100; if (glocal.ctx->login()!=-1){ while (!glocal.stop){ (*glocal.ctx,glocal.owner,false,glocal.offset,glocal.chunk); if (!success){ bofs_error ("msgs",internal_error,msg); glocal.stop = true; }else{ for (auto &m:messages){ printf ("%-10s %-10s %-10s %-10s %-30s %-20s %s %s\n",m.from,m.manager,m.project,m.role,m.uuid,m.submit,tbviewed[m.viewed]->get(),m.title); } glocal.stop = messages.size() < glocal.chunk; glocal.offset += glocal.chunk; } } } }else if (glocal.listshortmsgs){ glocal bool stop = false; glocal unsigned offset=0; glocal unsigned chunk=20; bofs_check_groupopt (glocal.groupname,glocal.groupowner); if (glocal.ctx->login()!=-1){ while (!glocal.stop){ (*glocal.ctx,glocal.owner,glocal.groupname,glocal.groupowner ,glocal.offset,glocal.chunk,glocal.firstseen); if (!success){ bofs_error ("msgs",internal_error,msg); glocal.stop = true; }else{ vector copy; bofs_copysort (messages,copy); if (nbnew > 0) printf (MSG_U(I_HIDDENNEWMESSAGES,"%u hidden new messages\n"),nbnew); bofs_listshortmsgs(*glocal.ctx,copy,glocal.full); glocal.stop = messages.size() < glocal.chunk; glocal.offset += glocal.chunk; } } } }else if (glocal.list){ if (glocal.ctx->login()!=-1){ (*glocal.ctx,glocal.owner); if (!success){ bofs_error ("msgs",internal_error,msg); }else{ unsigned max_manager=0; unsigned max_project=0; for (int r=0; r<2; r++){ for (auto &inb:inboxes){ bofs_maxlen (inb.manager,max_manager); bofs_maxlen (inb.project,max_project); if (r==1) printf ("%-*s %-*s %s\n",max_manager,inb.manager,max_project,inb.project,inb.role); } } glocal.ret = 0; } } }else if (glocal.newmsg){ if (glocal.content == NULL && glocal.filecontent == NULL){ bofs_error ("msgs",false,"Missing content"); }else{ glocal string buf; if (glocal.filecontent != NULL){ (glocal.filecontent,false); glocal.buf += line; return 0; glocal.content = glocal.buf.c_str(); } if (glocal.ctx->login()!=-1){ if (glocal.recipients.size() > 0){ (*glocal.ctx,glocal.owner ,glocal.recipients,glocal.title,glocal.content); if (!success){ bofs_error ("msgs",internal_error,msg); }else{ printf ("msgid: %s\n",msgid); glocal.ret = 0; } }else if (glocal.project != NULL && glocal.manager != NULL){ (*glocal.ctx,glocal.owner ,glocal.manager,glocal.project,glocal.role,glocal.title,glocal.content); if (!success){ bofs_error ("msgs",internal_error,msg); }else{ printf ("msgid: %s\n",msgid); glocal.ret = 0; } }else{ bofs_error ("msgs",false,"When sending a message, you must specify manager,project or recipients"); } } } }else if (glocal.shortmsg){ bofs_check_groupopt (glocal.recipients,glocal.groupname,glocal.groupowner); if (glocal.ctx->login()!=-1){ glocal.ret = bofs_send_talk(*glocal.ctx,glocal.content,glocal.filecontent,glocal.owner,glocal.recipients,glocal.groupname,glocal.groupowner); } }else if (glocal.shortmsg_file){ if (glocal.filename == NULL){ tlmp_error ("You must specify the filename\n"); }else if (glocal.ctx->login()!=-1){ bofs_check_groupopt (glocal.recipients,glocal.groupname,glocal.groupowner); glocal.ret = bofs_send_talk_file(*glocal.ctx,glocal.filename,"",glocal.owner,glocal.recipients,glocal.groupname,glocal.groupowner); } }else if (glocal.reply){ if (glocal.content == NULL && glocal.filecontent == NULL){ bofs_error ("msgs",false,"Missing content"); }else if (glocal.msgid == NULL){ bofs_error ("msgs",false,"You must specify the message ID you are replying to"); }else{ glocal string buf; if (glocal.filecontent != NULL){ (glocal.filecontent,false); glocal.buf += line; return 0; glocal.content = glocal.buf.c_str(); } if (glocal.ctx->login() != -1){ if (glocal.recipients.size() > 0){ (*glocal.ctx,glocal.owner ,glocal.msgid,glocal.recipients,glocal.title,glocal.content); if (!success){ bofs_error ("msgs",internal_error,msg); }else{ printf ("replyid: %s\n",replyid); glocal.ret = 0; } }else if (glocal.project != NULL && glocal.manager != NULL){ (*glocal.ctx,glocal.owner ,glocal.manager,glocal.project,glocal.role,glocal.msgid,glocal.title,glocal.content); if (!success){ bofs_error ("msgs",internal_error,msg); }else{ printf ("replyid: %s\n",replyid); glocal.ret = 0; } }else{ bofs_error ("msgs",false,"When sending a message, you must specify manager,project or recipients"); } } } }else if (glocal.attach){ }else{ usage(); } return glocal.ret; return glocal.ret; } static int bofs_config_read (CONTEXT &ctx, CONFIG &config, const char *owner) { glocal int ret = -1; glocal CONFIG *config = &config; if (ctx.is_internal()){ (ctx.con,ctx.sessionid,owner); if (!success){ bofs_error ("config_read",internal_error,msg); }else{ *glocal.config = config; glocal.ret = 0; } }else{ (ctx.hcon,ctx.hsessionid,owner); if (!success){ bofs_error ("https config_read",internal_error,msg); }else{ *glocal.config = config; glocal.ret = 0; } } return glocal.ret; } static int bofs_misc (CONTEXT &ctx, int argc, char *argv[]) { glocal int ret = -1; glocal CONTEXT *ctx = &ctx; glocal bool markview = false; glocal bool verifysign = false; glocal bool getpubkey = false; glocal const char *message = NULL; glocal const char *nickname = NULL; glocal unsigned nbrep=1; glocal bool contact_request = false; glocal bool contact_manage = false; glocal bool contact_list = false; glocal bool contact_request_by_me = false; glocal bool interest_set = false; glocal bool interest_unset = false; glocal bool interest_list = false; glocal bool interest_check = false; glocal vector fulltext; glocal const char *interest_user = NULL; glocal const char *status = "A"; glocal const char *intro = MSG_U(I_HELLOCONTACT,"Hello I would like to chat with you"); glocal const char *user = NULL; glocal const char *owner = ""; glocal bool showconfig = false; glocal bool writeconfig = false; // All config options are const char *, so they stay NULL if the user has not entered a value glocal const char *lang = NULL; glocal const char *public_view = NULL; glocal const char *public_dir = NULL; glocal const char *dateformat = NULL; glocal const char *anon_messages = NULL; glocal const char *timezone = NULL; glocal bool set_notification = false; glocal bool get_notification = false; glocal const char *notify_key = nullptr; glocal bool notify_ui = false; glocal bool notify_active_ui = false; glocal bool notify_email = false; glocal bool notify_digest = false; glocal const char *firstseen = ""; glocal.ret = (argc,argv); setproginfo ("bomisc",VERSION ,MSG_U(I_BOFSMISC,"Command line tool to do various things on Bolixo files\n" "\n" "bofs misc ...\n") ); setgrouparg (MSG_U(I_MAINCOMMAND,"Main commands")); setarg ('c',"showconfig","Show user configuration",glocal.showconfig,false); setarg ('w',"writeconfig","Update user configuration",glocal.writeconfig,false); setarg ('m',"markview","Mark a file as viewed",glocal.markview,false); setarg ('r',"contact_request","Ask a user to be part of his contact list",glocal.contact_request,false); setarg ('R',"contact_manage","Manage a contact request",glocal.contact_manage,false); setarg ('l',"contact_list","List the contacts for this user",glocal.contact_list,false); setarg ('I',"interest_set","Add one user to your interest list",glocal.interest_set,false); setarg ('U',"interest_unset","Remove one user from your interest list",glocal.interest_unset,false); setarg ('P',"interest_list","List members of your interest list",glocal.interest_list,false); setarg ('C',"interest_check","List messages of your interest list",glocal.interest_check,false); setarg ('v',"verifysign","Verify a message signature",glocal.verifysign,false); setarg (' ',"getpubkey","Get the public key of a user",glocal.getpubkey,false); setarg (' ',"set_notification",MSG_U(O_SET_NOTIFICATION,"Set notification configuration for a subject"),glocal.set_notification,false); setarg (' ',"get_notification",MSG_U(O_GET_NOTIFICATION,"Get notification configuration for a subject"),glocal.get_notification,false); setgrouparg (MSG_U(I_CONTACTMGMT,"contact management arguments")); setarg ('i',"intro","Introduction message for contact request",glocal.intro,false); setarg ('s',"status","New status of the contact request",glocal.status,false); setarg ('u',"user","User doing the contact request",glocal.user,false); setarg (' ',"request_by_me","(for contact_list) Show contact request made by me",glocal.contact_request_by_me,false); setgrouparg (MSG_U(I_INTERESTMGMT,"Interest management arguments")); setarg (' ',"int_user","User for interest_set and interest_unset",glocal.interest_user,false); setgrouparg (MSG_U(I_VERIYSIGN,"(http_)verifysign arguments")); setarg ('n',"nickname","User nickname who signed the message",glocal.nickname,false); setarg ('M',"message","Message to verify",glocal.message,false); setarg (' ',"nbrep","Number of repetition (performance test)",glocal.nbrep,false); setgrouparg (MSG_U(I_WRITECONFIG,"writeconfig options")); setarg ('F',"dateformat",MSG_U(O_DATEFORMAT,"Date presentation 0 or 1"),glocal.dateformat,false); setarg ('L',"lang",MSG_U(O_LANGUAGE,"Language used in the UI"),glocal.lang,false); setarg ('V',"public_view",MSG_U(O_PUBLICVIEW,"Enable public view (anonymous) 0 or 1"),glocal.public_view,false); setarg ('D',"public_dir",MSG_U(O_PUBLICDIR,"Select the sub-folder of the public project to display"),glocal.public_dir,false); setarg ('A',"anonmsgs",MSG_U(O_ANONMSGS,"Accept anonymous messages (0 or 1)"),glocal.anon_messages,false); setarg ('T',"timezone",MSG_U(O_TIMEZONE,"Time zone (file in /usr/share/zoneinfo)"),glocal.timezone,false); setgrouparg (MSG_R(I_NOTIFICATIONS)); setarg ('K',"notify_key",MSG_U(O_NOTIFY_KEY,"Notification subject"),glocal.notify_key,false); setarg (' ',"notify_ui",MSG_U(O_NOTIFY_UI,"Passive user interface notification"),glocal.notify_ui,false); setarg (' ',"notify_active_ui",MSG_U(O_NOTIFY_ACTIVE_UI,"Active user interface notification"),glocal.notify_active_ui,false); setarg (' ',"notify_email",MSG_U(O_NOTIFY_EMAIL,"Send notification email"),glocal.notify_email,false); setarg (' ',"notify_digest",MSG_U(O_NOTIFY_DIGEST,"Send notification digest"),glocal.notify_digest,false); setgrouparg (MSG_R(I_MISC)); setarg ('O',"owner",MSG_R(O_OWNER),glocal.owner,false); setarg (' ',"fulltext","Request full text for these messages",glocal.fulltext,false); setarg (' ',"firstseen",MSG_R(O_FIRSTSEEN),glocal.firstseen,false); glocal int ret = -1; if (glocal.markview){ glocal.ret = 0; if (glocal.ctx->login()!=-1){ for (int i=0; i(glocal.ctx->con,glocal.ctx->sessionid,argv[i]); if (!success){ bofs_error ("markview",internal_error,msg); glocal.ret = -1; } if (glocal.ret != 0) break; } } }else{ usage(); } return glocal.ret; glocal int ret = -1; if (glocal.verifysign){ if (glocal.nickname == NULL){ tlmp_error (MSG_U(E_NEEDNICKNAME,"You must provide the nickname\n")); exit (-1); } for (unsigned i=0; iis_internal()){ (glocal.ctx->con,glocal.nickname,glocal.message); if (status == ERR_CODE_NONE) glocal.ret = 0; printf ("\tverifysign: status=%d %s\n",status,msg); }else{ (glocal.ctx->hcon,glocal.nickname,glocal.message); if (status == ERR_CODE_NONE) glocal.ret = 0; printf ("\thttp_verifysign: status=%d %s\n",status,msg); } } }else if (glocal.getpubkey){ if (glocal.nickname == NULL){ tlmp_error (MSG_R(E_NEEDNICKNAME)); exit (-1); } (*glocal.ctx,glocal.nickname); if (success) glocal.ret = 0; printf ("\tgetpubkey: success=%d %s\n",success,pubkey); }else if (glocal.contact_manage){ if (glocal.user == NULL){ tlmp_error ("You must specify the user you want to manage\n"); exit (-1); } if (glocal.ctx->login()!=-1){ CONTACT_STATUS status = CONTACT_WAITING; if (strcmp(glocal.status,"A")==0){ status = CONTACT_ACCEPTED; }else if (strcmp(glocal.status,"R")==0){ status = CONTACT_REJECTED; }else{ tlmp_error ("Invalid status: expect A or R\n"); exit (-1); } if (glocal.ctx->is_internal()){ (glocal.ctx->con,glocal.ctx->sessionid,glocal.owner,glocal.user,status); if (!success){ bofs_error ("contact_manage",internal_error,msg); glocal.ret = -1; } }else{ (glocal.ctx->hcon,glocal.ctx->hsessionid,glocal.owner,glocal.user,status); if (!success){ bofs_error ("contact_manage",internal_error,msg); glocal.ret = -1; } } } }else if (glocal.contact_request){ if (glocal.user == NULL){ tlmp_error ("You must specify the user you want to contact\n"); exit (-1); } if (glocal.ctx->login()!=-1){ if (glocal.ctx->is_internal()){ (glocal.ctx->con,glocal.ctx->sessionid,glocal.owner,glocal.user,glocal.intro); if (!success){ bofs_error ("contact_request",internal_error,msg); glocal.ret = -1; } }else{ (glocal.ctx->hcon,glocal.ctx->hsessionid,glocal.owner,glocal.user,glocal.intro); if (!success){ bofs_error ("contact_request",internal_error,msg); glocal.ret = -1; } } } }else if (glocal.contact_list){ if (glocal.ctx->login()!=-1){ if (glocal.ctx->is_internal()){ (glocal.ctx->con,glocal.ctx->sessionid,glocal.owner,!glocal.contact_request_by_me,"",0,1000); if (!success){ bofs_error ("contact_list",internal_error,msg); glocal.ret = -1; }else{ static const char *tbstatus[]={"waiting","accepted","rejected"}; for (auto &c:contacts){ printf ("%s\t%s\t%s\t%s\n",c.user,c.reqdate,tbstatus[c.status],c.message); } } }else{ (glocal.ctx->hcon,glocal.ctx->hsessionid,glocal.owner,!glocal.contact_request_by_me,"",0,1000); if (!success){ bofs_error ("contact_list",internal_error,msg); glocal.ret = -1; }else{ static const char *tbstatus[]={"waiting","accepted","rejected"}; for (auto &c:contacts){ printf ("%s\t%s\t%s\t%s\n",c.user,c.reqdate,tbstatus[c.status],c.message); } } } } }else if (glocal.interest_set){ if (glocal.interest_user == NULL){ tlmp_error (MSG_U(E_INTUSER,"You must specify the user with --int_user\n")); exit (-1); }else if (glocal.ctx->login()!=-1){ if (glocal.ctx->is_internal()){ (glocal.ctx->con,glocal.ctx->sessionid,glocal.interest_user,glocal.owner); if (!success){ bofs_error ("interest_set",internal_error,msg); glocal.ret = -1; } }else{ notdone(); // interest_set } } }else if (glocal.interest_unset){ if (glocal.interest_user == NULL){ tlmp_error (MSG_R(E_INTUSER)); exit (-1); }else if (glocal.ctx->login()!=-1){ if (glocal.ctx->is_internal()){ (glocal.ctx->con,glocal.ctx->sessionid,glocal.interest_user,glocal.owner); if (!success){ bofs_error ("interest_unset",internal_error,msg); glocal.ret = -1; } }else{ notdone(); // interest_unset } } }else if (glocal.interest_list){ if (glocal.ctx->login()!=-1){ if (glocal.ctx->is_internal()){ (glocal.ctx->con,glocal.ctx->sessionid,glocal.owner); if (!success){ bofs_error ("interest_list",internal_error,msg); glocal.ret = -1; }else{ for (auto u:users){ printf ("%s %s %d\n",u.name,normalize_date(u.since),u.visible); } } }else{ notdone(); // interest_list } } }else if (glocal.interest_check){ if (glocal.ctx->login()!=-1){ glocal bool stop = false; glocal unsigned offset=0; glocal unsigned chunk=20; while (!glocal.stop){ (glocal.ctx->con,glocal.ctx->sessionid,glocal.owner ,glocal.fulltext,glocal.offset,glocal.chunk,glocal.firstseen); if (!success){ bofs_error ("interest_check",internal_error,msg); glocal.stop = true; }else{ vector copy; bofs_copysort (messages,copy); if (nbnew > 0) printf (MSG_R(I_HIDDENNEWMESSAGES),nbnew); for (auto &m:copy){ int linelen = 0; if (m.content[0] != '\0'){ const char *eol = strchr(m.content,'\n'); if (eol != NULL){ linelen=(eol-m.content); }else{ linelen = strlen(m.content); } } printf ("%s %-10s %-30s %-20s %7u %*.*s\n",tbftype[m.file_type],m.from ,normalize_uuid(m.uuid).c_str() ,normalize_date(m.submit),normalize_size(m.size) ,linelen,linelen,m.content); if (find(glocal.fulltext.begin(),glocal.fulltext.end(),m.uuid) != glocal.fulltext.end()){ printf ("%s\n",m.content); } } glocal.stop = messages.size() < glocal.chunk; glocal.offset += glocal.chunk; } } } }else if (glocal.showconfig){ if (glocal.ctx->login()!=-1){ CONFIG config; if (bofs_config_read (*glocal.ctx,config,glocal.owner)!=-1){ printf ("lang=%s dateformat=%u public_view=%d public_dir=%s anon_messages=%d timezone=%s\n" ,config.lang.c_str(),config.dateformat,config.public_view ,config.public_dir.c_str(),config.anon_messages,config.timezone.c_str()); } } }else if (glocal.writeconfig){ if (glocal.ctx->login()!=-1){ CONFIG config; if (bofs_config_read (*glocal.ctx,config,glocal.owner)!=-1){ CONFIG newconfig; newconfig = config; if (glocal.dateformat != NULL) newconfig.dateformat = atoi(glocal.dateformat); if (glocal.lang != NULL) newconfig.lang = glocal.lang; if (glocal.public_view != NULL) newconfig.public_view = atoi(glocal.public_view); if (glocal.public_dir != NULL) newconfig.public_dir = glocal.public_dir; if (glocal.anon_messages != NULL) newconfig.anon_messages = atoi(glocal.anon_messages); if (glocal.timezone != NULL) newconfig.timezone = glocal.timezone; if (glocal.ctx->is_internal()){ (glocal.ctx->con,glocal.ctx->sessionid,glocal.owner,newconfig); if (!success){ bofs_error ("config_write",internal_error,msg); } }else{ (glocal.ctx->hcon,glocal.ctx->hsessionid,glocal.owner,newconfig); if (!success){ bofs_error ("https config_write",internal_error,msg); } } } } }else if (glocal.get_notification){ if (glocal.notify_key == nullptr){ tlmp_error (MSG_U(E_NOTIFY_KEY,"You must specify the notification subject, option --notify_key\n")); }else if (glocal.ctx->login()!=-1){ if (glocal.ctx->is_internal()){ (glocal.ctx->con,glocal.ctx->sessionid,glocal.owner,glocal.notify_key); printf ("set_notification success=%d msg=%s ui=%d active_ui=%d email=%d digest=%d\n" ,success,msg,ui,active_ui,email,digest); }else{ notdone(); } } }else if (glocal.set_notification){ if (glocal.notify_key == nullptr){ tlmp_error (MSG_R(E_NOTIFY_KEY)); }else if (glocal.ctx->login()!=-1){ if (glocal.ctx->is_internal()){ (glocal.ctx->con,glocal.ctx->sessionid,glocal.owner ,glocal.notify_key,glocal.notify_ui,glocal.notify_active_ui,glocal.notify_email,glocal.notify_digest); printf ("set_notification success=%d msg=%s\n",success,msg); }else{ notdone(); } } }else{ usage(); glocal.ret = -1; } return glocal.ret; return glocal.ret; } static int bofs_public (CONTEXT &ctx, int argc, char *argv[]) { glocal int ret = -1; glocal CONTEXT *ctx = &ctx; glocal const char *listdir = NULL; glocal bool listshortmsgs = false; glocal const char *readfile = NULL; glocal const char *user = NULL; glocal bool use_http = false; glocal const char *output = NULL; glocal bool full = false; glocal.ret = (argc,argv); setproginfo ("bopublic",VERSION ,"Command line tool to test the public accesses\n" "\n" "bofs public ...\n" ); setgrouparg ("Main commands"); setarg ('l',"listdir","List content of a directory",glocal.listdir,false); setarg ('r',"readfile","Read one file",glocal.readfile,false); setarg ('s',"listshortmsgs",MSG_R(O_LISTSHORTMSGS),glocal.listshortmsgs,false); setarg ('u',"user","Specify the owner of the public files",glocal.user,true); setarg ('h',"http","Use HTTP",glocal.use_http,false); setarg ('O',"output","Copy readfile into this file",glocal.output,false); setarg (' ',"full",MSG_R(O_FULL),glocal.full,false); glocal int ret = 0; if (glocal.listdir != NULL){ glocal bool done = false; unsigned offset = 0; while (!glocal.done){ if (glocal.use_http){ (glocal.ctx->hcon,glocal.user,glocal.listdir,offset,20); if (!success){ glocal.done = true; bofs_error ("public_listdir",internal_error,msg); glocal.ret = -1; }else{ bofs_printdir (true,files,false); if (files.size() < 20) glocal.done = true; } }else{ (glocal.ctx->con,glocal.user,glocal.listdir,offset,20); if (!success){ glocal.done = true; bofs_error ("public_listdir",internal_error,msg); glocal.ret = -1; }else{ bofs_printdir (true,files,false); if (files.size() < 20) glocal.done = true; } } offset += 20; } }else if (glocal.readfile != NULL){ glocal FILE *fout = stdout; glocal bool done = false; glocal unsigned offset = 0; while (!glocal.done){ if (glocal.use_http){ (glocal.ctx->hcon,glocal.user,glocal.readfile,glocal.offset); if (!success){ glocal.done = true; bofs_error ("public_readfile",internal_error,msg); glocal.ret = -1; }else{ if (!more) glocal.done = true; glocal.offset += content.getsize(); fwrite (content.getbuffer(),1,content.getsize(),glocal.fout); } }else{ (glocal.ctx->con,glocal.user,glocal.readfile,glocal.offset); if (!success){ glocal.done = true; bofs_error ("public_readfile",internal_error,msg); glocal.ret = -1; }else{ if (!more) glocal.done = true; glocal.offset += content.getsize(); fwrite (content.getbuffer(),1,content.getsize(),glocal.fout); } } } }else if (glocal.listshortmsgs){ glocal bool done = false; unsigned offset = 0; while (!glocal.done){ if (glocal.use_http){ (glocal.ctx->hcon,glocal.user,offset,20); if (!success){ glocal.done = true; bofs_error ("public_listshortmsgs",internal_error,msg); glocal.ret = -1; }else{ bofs_listshortmsgs (*glocal.ctx,messages,glocal.full); if (messages.size() < 20) glocal.done = true; } }else{ (glocal.ctx->con,glocal.user,offset,20); if (!success){ glocal.done = true; bofs_error ("public_listshortmsgs",internal_error,msg); glocal.ret = -1; }else{ bofs_listshortmsgs (*glocal.ctx,messages,glocal.full); if (messages.size() < 20) glocal.done = true; } } offset += 20; } }else{ glocal.ret = -1; usage(); } return glocal.ret; return glocal.ret; } static int bofs_undelete (CONTEXT &ctx, int argc, char *argv[]) { glocal int ret = -1; glocal CONTEXT *ctx = &ctx; glocal const char *dir = NULL; glocal.ret = (argc,argv); setproginfo ("boundelete",VERSION ,"Command line tool to undelete bolixo files and directories\n" "\n" "bofs undelete parent-dir ...\n" ); glocal int ret = 0; glocal.ret = (*glocal.ctx,argc,argv); glocal int ret = -1; glocal const char *path = path; (ctx.con,ctx.sessionid,path); if (success){ glocal.ret = 0; }else{ bofs_error ("undelete",internal_error,MSG_U(E_CANTUNDELETE,"Can't undelete in folder %s: %s"),glocal.path,msg); } return glocal.ret; glocal int ret = -1; glocal const char *path = path; (ctx.hcon,ctx.hsessionid,path); if (success){ glocal.ret = 0; }else{ bofs_error ("rm",internal_error,MSG_R(E_CANTUNDELETE),glocal.path,msg); } return glocal.ret; return system (string_f("rm %s",path).c_str()); return glocal.ret; return glocal.ret; } static int bofs_bolixoapi_login( CONNECT_HTTP_INFO &hcon, // Connection info to the bolixo directory CONNECT_INFO &con, // Connection info to the local bolixo system const char *nodename, // This system nodename as seen by the bolixo directory string &session) { glocal string *session = &session; glocal CONNECT_HTTP_INFO *hcon = &hcon; glocal CONNECT_INFO *con = &con; glocal int ret = -1; (hcon,nodename); debug_printf ("nodelogin: internal_error=%d success=%d msg=%s session=%s\n",internal_error,success,msg,session); if (success){ glocal string sign; *glocal.session = session; CONNECT_INFO con_key; (*glocal.con,session); glocal.sign = sign; debug_printf ("bolixoapi_login sign=%s\n",glocal.sign.c_str()); (*glocal.hcon,session,glocal.sign); debug_printf ("nodepass: internal_error=%d success=%d msg=%s\n",internal_error,success,msg); if (success){ glocal.ret = 0; }else{ bofs_error ("bolixoapi_login nodepass",internal_error,"success=%d msg=%s\n",success,msg); } }else{ bofs_error ("bolixoapi_login nodelogin",internal_error," success=%d msg=%s session=%s\n",success,msg,session); } return glocal.ret; } static void bofs_bolixoapi_logout(CONNECT_HTTP_INFO &hcon, string &session) { (hcon,session); debug_printf ("nodelogout: internal_error=%d success=%d msg=%s\n",internal_error,success,msg); if (!success){ bofs_error ("bolixoapi nodelogout",internal_error,"success=%d msg=%s\n",success,msg); } } static void bofs_loadimage (BOB_TYPE &img, const char *fname) { img.clear(); FILE *fin = fopen (fname,"r"); if (fin != NULL){ char buf[100000]; int n = fread (buf,1,sizeof(buf),fin); if (n>0){ img.setbuffer(buf,n,true); } fclose (fin); } } static string dirserver("https://bolixo.org"); static int bofs_bolixoapi (CONTEXT &ctx, int argc, char *argv[]) { glocal int ret = -1; glocal CONTEXT *ctx = &ctx; // Info for publish glocal bool filldummy = false; glocal const char *fullname = ""; glocal const char *address1 = ""; glocal const char *address2 = ""; glocal const char *city = ""; glocal const char *state = ""; glocal const char *country = ""; glocal const char *zipcode = ""; glocal const char *email = ""; glocal const char *phone = ""; glocal const char *fax = ""; glocal const char *bolixosite = ""; glocal const char *website = ""; glocal const char *interest = ""; glocal const char *photo = nullptr; glocal const char *mini_photo = nullptr; glocal bool publish = false; glocal bool publish_photo = false; glocal bool publish_mini_photo = false; glocal bool publish_bolixosite = false; glocal.ret = (argc,argv); setproginfo ("bofs bolixoapi",VERSION ,MSG_U(I_BOLIXOAPI ,"Command line tool to test inter node communication\n" "\n" "bofs bolixoapi command ...\n" "\n" "Commands are:\n" "\ttest\n" "\tinforead\n" "\tinfowrite\n" "\tsystempubkey\n" "\tsystemsign msg\n" "\tregisternode node-url\n" "\tnodelogin directory_url\n" "\tnodelogout directory_url\n" "\tpublish directory_url user\n" "\tremove directory_url user\n" "\trecordemail thisnode_url userid email\n" "\tupdate directory_url user\n" ) ); setarg ('d',"directory-server","Server hosting the Bolixo directory",dirserver,false); setgrouparg (MSG_U(O_PUBLISHDATA,"publish data")); setarg (' ',"publish",MSG_U(O_PUBLISH,"Publish to the bolixo.org directory"),glocal.publish,false); setarg (' ',"publish_bosite",MSG_U(O_PUBLISH_BOSITE,"Publish the user public page"),glocal.publish_bolixosite,false); setarg (' ',"publish_photo",MSG_U(O_PUBLISH_PHOTO,"Publish the photo"),glocal.publish_photo,false); setarg (' ',"publish_mini_photo",MSG_U(O_PUBLISH_MINI_PHOTO,"Publish the mini photo"),glocal.publish_mini_photo,false); setarg (' ',"filldummy",MSG_U(O_FILLDUMMY,"Fill dummy values is all fields"),glocal.filldummy,false); setarg (' ',"fullname",MSG_U(O_FULLNAME,"Full name of the user"),glocal.fullname,false); setarg (' ',"address1",MSG_U(O_ADDRESS1,"First line of address"),glocal.address1,false); setarg (' ',"address2",MSG_U(O_ADDRESS2,"Second line of address"),glocal.address2,false); setarg (' ',"city",MSG_U(O_CITY,"City"),glocal.city,false); setarg (' ',"state",MSG_U(O_STATE,"State"),glocal.state,false); setarg (' ',"country",MSG_U(O_COUNTRY,"Country"),glocal.country,false); setarg (' ',"zipcode",MSG_U(O_ZIPCODE,"Zip code"),glocal.zipcode,false); setarg (' ',"email",MSG_U(O_EMAIL,"Email"),glocal.email,false); setarg (' ',"phone",MSG_U(O_PHONE,"Phone"),glocal.phone,false); setarg (' ',"fax",MSG_U(O_FAX,"Fax"),glocal.fax,false); setarg (' ',"bolixosite",MSG_U(O_BOLIXOSITE,"Bolixo site"),glocal.bolixosite,false); setarg (' ',"website",MSG_U(O_WEBSITE,"Web site"),glocal.website,false); setarg (' ',"interest",MSG_U(O_INTEREST,"Interests"),glocal.interest,false); setarg (' ',"photo",MSG_U(O_PHOTO,"Path of the large photo of the user"),glocal.photo,false); setarg (' ',"mini_photo",MSG_U(O_MINIPHOTO,"Path of the small photo of the user"),glocal.mini_photo,false); glocal int ret = 0; { string host,port,path; if (bofs_split_http(*glocal.ctx,dirserver.c_str(),host,port,path)==-1){ tlmp_error (MSG_U(E_IVLDDIRSERVERURL,"Invalid URL for the Bolixo directory server: %s\n") ,dirserver.c_str()); exit (-1); } } glocal.ctx->hcon.setpageapi("bolixoapi"); if (nonstrict) glocal.ctx->hcon.setnonstrictmode(); const char *arg = argv[0]; if (strcmp(arg,"test")==0 && argc == 1){ (glocal.ctx->hcon); printf ("internal=%d msg=%s sessiond=%d db=%d\n",internal_error,msg,sessiond,db); }else if (strcmp(arg,"systempubkey")==0 && argc == 1){ glocal.ctx->hcon.setpageapi("webapi"); (glocal.ctx->hcon); printf ("internal_error=%d pubkey=%s\n",internal_error,pubkey); }else if (strcmp(arg,"systemsign")==0 && argc==2){ (glocal.ctx->con,argv[1]); printf ("internal_error=%d sign=%s\n",internal_error,sign); }else if (strcmp(arg,"registernode")==0 && argc==2){ (glocal.ctx->hcon,argv[1]); debug_printf ("registernode internal_error=%d success=%d msg=%s\n",internal_error,success,msg); if (!success){ bofs_error ("registernode",internal_error,"success=%d msg=%s\n",success,msg); } }else if (strcmp(arg,"nodelogin")==0 && argc==2){ string session; if (bofs_bolixoapi_login (glocal.ctx->hcon,glocal.ctx->con,argv[1],session)!=-1){ (glocal.ctx->hcon,session); printf ("nodelogout: internal_error=%d success=%d msg=%s\n",internal_error,success,msg); } }else if (strcmp(arg,"nodelogout")==0 && argc==2){ (glocal.ctx->hcon,argv[1]); printf ("nodelogout: internal_error=%d success=%d msg=%s\n",internal_error,success,msg); }else if (strcmp(arg,"publish")==0 && argc>=3){ const char *nodename = argv[1]; const char *user = argv[2]; string session; if (bofs_bolixoapi_login (glocal.ctx->hcon,glocal.ctx->con,nodename,session)!=-1){ USERINFO info; info.user = user; if (glocal.filldummy){ info.fullname = string_f("full %s",user); info.address1 = string_f("%s street 1",user); info.address2 = string_f("%s street 2",user); info.city = string_f("%s city",user); info.state = string_f("%s state",user); info.country = string_f("%s country",user); info.zipcode = string_f("%s zip",user); info.email = string_f("%s email",user); info.phone = string_f("%s phone",user); info.fax = string_f("%s fax",user); info.bolixosite = string_f("%s bolixosite",user); info.website = string_f("%s website",user); for (unsigned i=0; i<5; i++){ info.interest += string_f("%s is interested in various topics such as this one
\n",user); } bofs_loadimage (info.photo,"/tmp/photo.jpg"); bofs_loadimage (info.mini_photo,"/tmp/mini-photo.jpg"); }else{ info.fullname = glocal.fullname; info.address1 = glocal.address1; info.address2 = glocal.address2; info.city = glocal.city; info.state = glocal.state; info.country = glocal.country; info.zipcode = glocal.zipcode; info.email = glocal.email; info.phone = glocal.phone; info.fax = glocal.fax; info.bolixosite = glocal.bolixosite; info.website = glocal.website; info.interest = glocal.interest; if (glocal.photo != nullptr) bofs_loadimage (info.photo,glocal.photo); if (glocal.mini_photo != nullptr) bofs_loadimage (info.mini_photo,glocal.mini_photo); } (glocal.ctx->hcon,session,info); debug_printf ("publish: internal_error=%d success=%d msg=%s\n",internal_error,success,msg); if (!success){ glocal.ret = -1; bofs_error ("bolixoapi publish",internal_error,"success=%d msg=%s\n",success,msg); } bofs_bolixoapi_logout (glocal.ctx->hcon,session); } }else if (strcmp(arg,"remove")==0 && argc==3){ const char *nodename = argv[1]; const char *user = argv[2]; string session; if (bofs_bolixoapi_login (glocal.ctx->hcon,glocal.ctx->con,nodename,session)!=-1){ (glocal.ctx->hcon,session,user); debug_printf ("remove: internal_error=%d success=%d msg=%s\n",internal_error,success,msg); if (!success){ glocal.ret = -1; bofs_error ("bolixoapi remove",internal_error,"success=%d msg=%s\n",success,msg); } bofs_bolixoapi_logout (glocal.ctx->hcon,session); } }else if (strcmp(arg,"update")==0 && argc==2){ const char *nodename = argv[1]; string session; if (glocal.ctx->login()==-1){ tlmp_error ("Local login failed, can't continue\n"); }else if (bofs_bolixoapi_login (glocal.ctx->hcon,glocal.ctx->con,nodename,session)!=-1){ glocal USERPUBLICINFO info; glocal bool success = false; (glocal.ctx->con,glocal.ctx->sessionid,""); glocal.success = success; if (!success){ glocal.ret = -1; tlmp_error ("info_read: internal_error=%d success=%d msg=%s\n",internal_error,success,msg); glocal.info = info; } if (glocal.success){ if (glocal.info.publish){ USERINFO info; info.user = glocal.ctx->user; info.fullname = glocal.info.fullname; info.address1 = glocal.info.address1; info.address2 = glocal.info.address2; info.city = glocal.info.city; info.state = glocal.info.state; info.country = glocal.info.country; info.zipcode = glocal.info.zipcode; info.email = glocal.info.email; info.phone = glocal.info.phone; info.fax = glocal.info.fax; info.bolixosite = glocal.info.bosite_visible ? string_f("http://test1.bolixo.org/public/%s",glocal.ctx->user.c_str()) : ""; info.website = glocal.info.website; info.interest = glocal.info.interest; (glocal.ctx->hcon,session,info); if (!success){ glocal.ret = -1; tlmp_error ("publish: internal_error=%d success=%d msg=%s\n",internal_error,success,msg); } }else{ (glocal.ctx->hcon,session,glocal.ctx->user); if (!success){ glocal.ret = -1; tlmp_error ("remove: internal_error=%d success=%d msg=%s\n",internal_error,success,msg); } } } bofs_bolixoapi_logout (glocal.ctx->hcon,session); } }else if (strcmp(arg,"recordemail")==0 && argc==4){ const char *nodename = argv[1]; const char *userid = argv[2]; const char *email = argv[3]; string session; if (bofs_bolixoapi_login (glocal.ctx->hcon,glocal.ctx->con,nodename,session)!=-1){ (glocal.ctx->hcon,session,userid,email); if (!success){ glocal.ret = -1; printf ("recordemail: internal_error=%d success=%d msg=%s\n",internal_error,success,msg); } bofs_bolixoapi_logout (glocal.ctx->hcon,session); } }else if (strcmp(arg,"infowrite")==0 && argc==1){ if (glocal.ctx->login()==-1){ tlmp_error ("Local login failed, can't continue\n"); }else{ const char *user = glocal.ctx->user.c_str(); USERPUBLICINFO info; if (glocal.filldummy){ info.publish = true; info.bosite_visible = true; info.fullname = string_f("full %s",user); info.address1 = string_f("%s street 1",user); info.address2 = string_f("%s street 2",user); info.city = string_f("%s city",user); info.state = string_f("%s state",user); info.country = string_f("%s country",user); info.zipcode = string_f("%s zip",user); info.email = string_f("%s email",user); info.phone = string_f("%s phone",user); info.fax = string_f("%s fax",user); info.bosite_visible = true; info.website = string_f("%s website",user); for (unsigned i=0; i<5; i++){ info.interest += string_f("%s is interested in various topics such as this one
\n",user); } info.mini_photo = true; info.photo = true; }else{ info.publish = glocal.publish; info.fullname = glocal.fullname; info.address1 = glocal.address1; info.address2 = glocal.address2; info.city = glocal.city; info.state = glocal.state; info.country = glocal.country; info.zipcode = glocal.zipcode; info.email = glocal.email; info.phone = glocal.phone; info.fax = glocal.fax; info.bosite_visible = glocal.publish_bolixosite; info.website = glocal.website; info.interest = glocal.interest; info.photo = glocal.publish_photo; info.mini_photo = glocal.publish_mini_photo; } (glocal.ctx->con,glocal.ctx->sessionid,"",info); if (!success){ glocal.ret = -1; tlmp_error ("infowrite: internal_error=%d success=%d msg=%s\n",internal_error,success,msg); } } }else if (strcmp(arg,"inforead")==0 && argc==1){ if (glocal.ctx->login()==-1){ tlmp_error ("Local login failed, can't continue\n"); }else{ (glocal.ctx->con,glocal.ctx->sessionid,""); if (!success){ glocal.ret = -1; tlmp_error ("inforead: internal_error=%d success=%d msg=%s\n",internal_error,success,msg); }else{ printf ("fullname=%s\n",info.fullname); printf ("address1=%s\n",info.address1); printf ("address2=%s\n",info.address2); } } }else{ usage(); } return glocal.ret;
return glocal.ret; }
static void strip_blank (string &s) { const char *pt = s.c_str(); while (isspace(*pt)) pt++; s = pt; strip_end (s); } static void bofs_loadconf(CONTEXT &ctx, const char *user) { glocal const char *user = user; glocal bool thisuser = false; glocal CONTEXT *ctx = &ctx; (string_f("%s/.bofs.conf",getenv("HOME")),true); int ret = 0; if (line[0] == '#') return 0; vector tb; const char *pt = strchr(line,':'); if (pt != NULL){ tb.push_back(string(line,pt-line)); tb.push_back(pt+1); } if (tb.size() >= 2){ for (auto &s:tb) strip_blank (s); const char *subject = tb[0].c_str(); if (strcmp(subject,"bolixo")==0){ dirserver = tb[1]; }else if (strcmp(subject,"user")==0){ if (glocal.thisuser){ ret = -1; }else if (glocal.user == NULL || strcmp(glocal.user,tb[1].c_str())==0){ glocal.thisuser = true; glocal.ctx->user = tb[1]; } }else if (glocal.thisuser){ if (strcmp(subject,"email")==0){ glocal.ctx->email = tb[1]; }else if (strcmp(subject,"password")==0){ glocal.ctx->password = tb[1]; }else if (strcmp(subject,"http_server")==0){ glocal.ctx->hcon.host = tb[1]; }else if (strcmp(subject,"http_port")==0){ glocal.ctx->hcon.port = tb[1]; if (tb[1] == "443") glocal.ctx->hcon.use_ssl = true; }else if (strcmp(subject,"bod_socket")==0){ glocal.ctx->con.port = tb[1]; }else if (strcmp(subject,"sess_socket")==0){ glocal.ctx->con_sess.port = tb[1]; }else if (strcmp(subject,"bod_secret")==0){ glocal.ctx->con.secret = tb[1]; }else if (strcmp(subject,"sess_secret")==0){ glocal.ctx->con_sess.secret = tb[1]; }else{ tlmp_error (MSG_U(E_KEYWORD,"File %s, invalid keyword: %s\n"),info.filename,subject); } } } return ret; tlmp_error (MSG_U(E_CONFMISSING,"File %s/.bofs.conf missing.\n"),getenv("HOME")); tlmp_error (MSG_U(I_BOFSCONF,"Create this file with the following fields:\n" "\tuser:\n" "\temail:\n" "\tpassword:\n" "\tbod_socket:\n" "\tsess_socket:\n" "\tbod_secret:\n" "\tsess_secret:\n" "\thttp_server:\n" "\thttp_port:\n")); exit (-1); if (!glocal.thisuser){ tlmp_error (MSG_U(E_NOUSER,"No user definition found in .bofs.conf for user %s\n"),glocal.user); exit (-1); } } int main (int argc, char *argv[]) { glocal int ret = -1; glocal const char *user = NULL; glocal bool printcred = false; glocal int nbrep=1; glocal const char *uuidfile = "/tmp/bofs.testuuids"; glocal const char *session = NULL; glocal bool login = false; glocal bool logout = false; glocal bool clearpubcache = false; glocal bool listpubcache = false; glocal const char *pubsite = NULL; glocal const char *pubuser = NULL; glocal.ret = (argc,argv,"bolixo"); setproginfo ("bofs",VERSION ,MSG_U(I_BOFS,"Command line tool to perform file-system operations on Bolixo\n" "\n" "\tbofs bolixoapi ...\n" "\tbofs cat ...\n" "\tbofs cp ...\n" "\tbofs groups ...\n" "\tbofs ls ...\n" "\tbofs misc ...\n" "\tbofs mkdir ...\n" "\tbofs msgs ...\n" "\tbofs mv ...\n" "\tbofs public ...\n" "\tbofs rm ...\n" "\tbofs rmdir ...\n" "\tbofs undelete dir\n") ); setarg ('u',"user",MSG_U(O_SELECT,"Select one user from .bofs.conf"),glocal.user,false); setarg (' ',"nonstrict",MSG_U(O_NONSTRICT,"Allow SSL connection to self-sign certificate"),nonstrict,false); setgrouparg (MSG_U(H_TESTS,"Tests")); setarg (' ',"repeat",MSG_U(O_REPEAT,"Repeat the operation N time (speed test)"),glocal.nbrep,false); setarg ('t',"testmode",MSG_U(O_TESTMODE,"Test mode, normalize output"),testmode,false); setarg (' ',"uuidfile",MSG_U(O_UUIDFILE,"File holding collected uuids for testmode"),glocal.uuidfile,false); setarg (' ',"printcred",MSG_U(O_PRINTCRED,"Print email and password of the user from .bofs.conf"),glocal.printcred,false); setarg (' ',"login",MSG_U(O_LOGIN,"Just do a login and print the session id"),glocal.login,false); setarg (' ',"logout",MSG_U(O_LOGOUT,"Logout the supplied session id"),glocal.logout,false); setarg (' ',"session",MSG_U(O_SESSION,"Session id obtained from --login"),glocal.session,false); setgrouparg (MSG_U(O_PUBKEYCACHE,"Public key cache")); setarg (' ',"clearpubcache",MSG_U(O_CLEARPUBCACHE,"Erase parts of the public key cache"),glocal.clearpubcache,false); setarg (' ',"listpubcache",MSG_U(O_LISTPUBCACHE,"List parts of the public key cache"),glocal.listpubcache,false); setarg (' ',"pubsite",MSG_U(O_PUBSITE,"Clear/List for this site\n(use 'all' to match all sites)"),glocal.pubsite,false); setarg (' ',"pubuser",MSG_U(O_PUBUSER,"Clear/List for this user"),glocal.pubuser,false); int ret = -1; if (glocal.printcred){ CONTEXT ctx; bofs_loadconf(ctx,glocal.user); printf ("export WEBTEST_EMAIL=%s\nexport WEBTEST_PASSWORD=%s\n",ctx.email.c_str(),ctx.password.c_str()); ret = 0; }else if (glocal.login){ CONTEXT ctx; bofs_loadconf(ctx,glocal.user); if (ctx.login()!=-1){ if (ctx.sessionid.size() > 0){ printf ("%s\n",ctx.sessionid.c_str()); }else{ printf ("%s\n",ctx.hsessionid.c_str()); } // Prevent the logout by CONTEXT destructor ctx.hsessionid.clear(); ctx.sessionid.clear(); ret = 0; } }else if (glocal.logout){ CONTEXT ctx; bofs_loadconf(ctx,glocal.user); if (glocal.session == NULL){ tlmp_error (MSG_U(E_NEEDSESSIONID,"You must provide the session id (got using --login)\n")); }else if (ctx.is_internal()){ ctx.sessionid = glocal.session; }else{ ctx.hsessionid = glocal.session; } // CONTEXT destructor will perform the logout }else if (glocal.clearpubcache || glocal.listpubcache){ if (glocal.pubuser == NULL && glocal.pubsite == NULL){ tlmp_error (MSG_U(E_PUBACTION,"You must specify one of the following option: --pubsite or --pubuser\n")); }else{ bofs_loadpubcache(); bool modified = false; if (glocal.pubuser != NULL){ auto p = pubkeys.find(glocal.pubuser); if (p == pubkeys.end()){ tlmp_error (MSG_U(E_NOCACHEPUBKEY,"No public key found in cache for user %s\n"),glocal.user); }else if (glocal.listpubcache){ printf ("%s\n",p->second.c_str()); }else if (glocal.clearpubcache){ pubkeys.erase(p); modified = true; } } if (glocal.pubsite){ for (auto p=pubkeys.begin(); p != pubkeys.end(); ){ auto next = p; next++; const char *user = p->first.c_str(); const char *pt = strchr(user,'@'); if (pt == NULL){ tlmp_error (MSG_U(E_IVLDPUBUSER,"Invalid user entry in public key cache: %s\n"),user); }else if (strcmp(glocal.pubsite,"all")==0 || strcasecmp(pt+1,glocal.pubsite)==0){ if (glocal.listpubcache){ printf ("%s\n",user); }else if (glocal.clearpubcache){ pubkeys.erase (p); modified = true; } } p=next; } } if (modified){ (bofs_pubcachefile(),false); for (auto p:pubkeys){ fprintf (fout,"#%s\n%s",p.first.c_str(),p.second.c_str()); } return 0; } } }else{ usage(); } return ret; int ret = -1; glocal CONTEXT ctx; if (testmode) load_normalize_uuids(glocal.uuidfile); bofs_loadconf(glocal.ctx,glocal.user); if (glocal.printcred){ printf ("export WEBTEST_EMAIL=%s\nexport WEBTEST_PASSWORD=%s\n",glocal.ctx.email.c_str(),glocal.ctx.password.c_str()); }else{ if (glocal.session != NULL){ if (glocal.ctx.is_internal()){ glocal.ctx.sessionid = glocal.session; }else{ glocal.ctx.hsessionid = glocal.session; } glocal.ctx.preset_session = true; } //printf ("ctx.hcon.host=%s ctx.hcon.port=%s\n",glocal.ctx.hcon.host.c_str(),glocal.ctx.hcon.port.c_str()); for (int i=0; i(glocal.uuidfile,false); for (auto &u:uuids){ fprintf (fout,"%s %u\n",u.first.c_str(),u.second); } return 0; } return ret; return glocal.ret; }