/* 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 . */ /* Manage public directory for all bolixo nodes. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "filesystem.h" #include "bolixo.h" #include "bolixo.m" #define INSTRUMENT_DONOTOPEN #include "instrument.h" using namespace std; static DEBUG_KEY D_PROTO ("proto","Protocol information"); enum CONNECT_TYPE { TYPE_NONE, TYPE_CONTROL, TYPE_CLIENT}; struct HANDLE_INFO: public ARRAY_OBJ{ CONNECT_TYPE type; REQUEST_INFO req; HANDLE_INFO(){ type = TYPE_NONE; } }; #define bo_sessiond_admin_getsessioninfo_NOTNEED #define bo_sessiond_admin_deletesessions_NOTNEED #define bo_sessiond_admin_setlang_NOTNEED #define bo_sessiond_admin_setnotify_NOTNEED #include "proto/bo-sessiond_admin.protoch" #define webapi_test_NOTNEED #define webapi_login_NOTNEED #define webapi_logout_NOTNEED #define webapi_addfile_NOTNEED #define webapi_addfile_bob_NOTNEED #define webapi_appendfile_NOTNEED #define webapi_delfile_NOTNEED #define webapi_undelete_NOTNEED #define webapi_modifyfile_NOTNEED #define webapi_modifyfile_bob_NOTNEED #define webapi_rename_NOTNEED #define webapi_copy_NOTNEED #define webapi_readfile_NOTNEED #define webapi_readfile_bob_NOTNEED #define webapi_readmore_NOTNEED #define webapi_mkdir_NOTNEED #define webapi_rmdir_NOTNEED #define webapi_listdir_NOTNEED #define webapi_stat_NOTNEED #define webapi_set_access_NOTNEED #define webapi_markview_NOTNEED #define webapi_verifysign_NOTNEED #define webapi_list_inboxes_NOTNEED #define webapi_list_msgs_NOTNEED #define webapi_sendmsg_NOTNEED #define webapi_sendmsg_project_NOTNEED #define webapi_replymsg_NOTNEED #define webapi_replymsg_project_NOTNEED #define webapi_sendattach_NOTNEED #define webapi_sendtalk_NOTNEED #define webapi_sendtalk_file_NOTNEED #define webapi_list_talk_NOTNEED #define webapi_public_listdir_NOTNEED #define webapi_public_readfile_NOTNEED #define webapi_public_list_talk_NOTNEED #define webapi_config_read_NOTNEED #define webapi_config_write_NOTNEED #define webapi_getpubkey_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 #define webapi_contact_manage_NOTNEED #define webapi_contact_request_NOTNEED #define webapi_contact_list_NOTNEED #define webapi_list_contacts_NOTNEED #define webapi_list_lists_NOTNEED #define webapi_list_groups_NOTNEED #define webapi_create_group_NOTNEED #define webapi_delete_group_NOTNEED #define webapi_delete_list_NOTNEED #define webapi_set_member_NOTNEED #define webapi_contact_remove_NOTNEED #define webapi_list_members_NOTNEED #define webapi_create_group_list_NOTNEED #define webapi_set_group_NOTNEED #define webapi_playstep_NOTNEED #define webapi_playstep_more_NOTNEED #include "proto/webapi.protoch" #include "proto/bolixod_control.protoh" #include "proto/bolixod_client.protoh" // Some tests to show everyting is connected static void bolixod_test (CONNECT_INFO &con_sess, string &msg, bool &sessiond_ok, bool &db_ok, bool &fsok) { glocal string msg; glocal bool sessiond_ok = false; glocal bool db_ok = false; glocal bool fsok = false; (con_sess); if (!success){ glocal.msg = "sessiond failed"; }else{ glocal.sessiond_ok = true; } ("select count(*) from nodes"); glocal.db_ok = true; static const char *testfile = "/var/lib/bolixod/test"; (testfile,false); glocal.fsok = true; return 0; unlink (testfile); sessiond_ok = glocal.sessiond_ok; db_ok = glocal.db_ok; fsok = glocal.fsok; msg = glocal.msg; } static bool nonstrict = false; static void bolixod_getpubkey (bool use_ssl, const char *hostname, const char *nodename, string &msg) { glocal string *msg = &msg; glocal const char *nodename = nodename; CONNECT_HTTP_INFO con; if (nonstrict) con.setnonstrictmode(); con.use_ssl = use_ssl; const char *pt = strchr(hostname,':'); if (pt == NULL){ con.host = hostname; con.port = use_ssl ? "443" : "80"; }else{ con.host = string(hostname,pt-hostname); con.port = pt+1; } (con); if (internal_error){ *glocal.msg = "internal_error webapi:systempubkey"; }else if (pubkey[0] != '\0'){ if (fs_valid_pubkey(pubkey)==-1){ *glocal.msg = string_f("Invalid pubkey for nodename %s",glocal.nodename); tlmp_error ("Inalid pubkey for nodename %s\n",glocal.nodename); }else{ if (sql_action("update nodes set created=now(),pub_key='%s' where nodename='%s'" ,pubkey,glocal.nodename)==-1){ *glocal.msg = "Internal error, inserting node pubkey"; tlmp_error ("Internal error, inserting node pubkey\n"); } } }else{ *glocal.msg = string_f("No pubkey for nodename %s",glocal.nodename); tlmp_error ("No pubkey for nodename %s\n",glocal.nodename); } } static void bolixod_getpubkey (const char *nodename, string &msg) { if (strncasecmp(nodename,"http://",7)==0){ bolixod_getpubkey(false,nodename+7,nodename,msg); }else if (strncasecmp(nodename,"https://",8)==0){ bolixod_getpubkey(true,nodename+8,nodename,msg); }else{ msg = string_f ("getpubkey invalid nodename: %s",nodename); tlmp_error ("getpubkey invalid nodename: %s\n",nodename); } } // Get the information of this session. // Return 1 for a new session // Return 2 for an established session (login done) // Return -1 for an invalid session static int bolixod_sessionstate( CONNECT_INFO &con_sess, PARAM_STRING session, unsigned expected_state, string &nodename, string &msg) { glocal CONNECT_INFO *con_sess = &con_sess; glocal const char *session = session.ptr; glocal unsigned expected = expected_state; glocal string *msg = &msg; glocal string *nodename = &nodename; glocal int ret = -1; (con_sess,session); if (internal_error){ *glocal.msg = "Internal error"; }else if (!success){ *glocal.msg = "Invalid session"; }else if (userid != glocal.expected){ //tlmp_error ("userid=%d expected=%d session=%s\n",userid,glocal.expected,glocal.session); *glocal.msg = "Invalid session"; (*glocal.con_sess,glocal.session); }else{ glocal.ret = userid; *glocal.nodename = userid_str; } return glocal.ret; } // Check if the nodename is a valid server URL static int bolixod_parsenode(const char *node, string &name) { int ret = 0; if (strncasecmp(node,"http://",7)==0){ node += 7; }else if (strncasecmp(node,"https://",8)==0){ node += 8; }else{ ret = -1; } if (ret != -1){ name = node; while (*node != '\0'){ if (*node == '/' || *node <= ' '){ ret = -1; break; } node++; } } return ret; } static int bolixod_validnode(const char *node) { string name; return bolixod_parsenode (node,name); } // Check if the nodename is a valid server URL and belongs to a domain static int bolixod_validnode(const char *node, const char *domain) { string name; int ret = bolixod_parsenode (node,name); if (ret != -1){ const char *start = name.c_str(); const char *pt = strchr(start,':'); if (pt != NULL){ name = string(start,pt-start); } // The nodename must be a sub-domain of the domain. Not the domain itself. start = name.c_str(); pt = strstr(start,domain); if (pt == NULL){ ret = -1; }else if (strcmp(pt,domain)!=0){ ret = -1; }else if (pt == start){ ret = -1; }else if (pt[-1] != '.'){ ret = -1; } //tlmp_error ("validnode name=:%s: domain=:%s: ret=%d\n",name.c_str(),domain,ret); } return ret; } // Check that a file (or a user id) is valid static int bolixod_validfile(const char *file) { int ret = 0; if (file[0] == '\0'){ ret = -1; }else{ while (*file != '\0'){ if (*file == '/' || *file <= ' '){ ret = -1; break; } file++; } } return ret; } static void bolixod_updatephoto (PARAM_STRING fname, const BOB_TYPE &img) { if (img.getsize()==0){ unlink (fname.ptr); }else{ FILE *fout = fopen (fname.ptr,"w"); if (fout == NULL){ tlmp_error ("Can't open file %s (%s)\n",fname.ptr,strerror(errno)); }else{ fwrite (img.getbuffer(),1,img.getsize(),fout); fclose (fout); } } } // Get the directory where photos are stored for this node static string bolixod_getnodedir(PARAM_STRING nodename) { string ret; const char *node = nodename.ptr; if (strncasecmp(node,"http://",7)==0){ node += 7; }else if (strncasecmp(node,"https://",8)==0){ node += 8; } return string_f("/var/lib/bolixod/%s",node); } // Set the status of the photos (they exist or not) static void bolixod_setphotos(USERPUBINFO &info) { string dir = bolixod_getnodedir(info.nodename); string tmp = string_f("%s/%s-photo.jpg",dir.c_str(),info.user.c_str()); struct stat st; if (stat(tmp.c_str(),&st)!=-1) info.photo = true; tmp = string_f("%s/%s-mini-photo.jpg",dir.c_str(),info.user.c_str()); if (stat(tmp.c_str(),&st)!=-1) info.mini_photo = true; } static string bolixod_getmodified(struct stat64 &st) { struct tm *t = localtime(&st.st_mtime); return string_f("%04d/%02d/%02d %2d:%2d:%2d" ,t->tm_year+1900,t->tm_mon+1,t->tm_mday ,t->tm_hour,t->tm_min,t->tm_sec); } // Set the status of the photos (they exist or not) // The status is the modified time. If empty, then the file is missing static void bolixod_setphotos(USERPUBINFO_V2 &info) { string dir = bolixod_getnodedir(info.nodename); string tmp = string_f("%s/%s-photo.jpg",dir.c_str(),info.user.c_str()); struct stat64 st; if (stat64(tmp.c_str(),&st)!=-1) info.photo_modified = bolixod_getmodified(st); tmp = string_f("%s/%s-mini-photo.jpg",dir.c_str(),info.user.c_str()); if (stat64(tmp.c_str(),&st)!=-1) info.mini_photo_modified = bolixod_getmodified(st); } int main (int argc, char *argv[]) { glocal int ret = -1; glocal unsigned clientport=0; glocal const char *dbserv = "localhost"; glocal const char *dbname = "files"; glocal const char *dbuser = "bolixo"; glocal const char *control = "/var/run/bolixod.sock"; glocal const char *user = "bolixo"; glocal const char *sessport = "/dev/sessiond.sock"; glocal const char *mysecret = NULL; glocal bool daemon = false; glocal const char *pidfile = "/var/run/bolixod.pid"; glocal const char *client_secretfile = "/etc/bolixo/secrets.client"; glocal const char *domain = "bolixo.org"; glocal unsigned maxaccts = 200; glocal bool devmode = false; static const char *tbdic[]={"tlmpsql","bolixo",NULL}; glocal.ret = (argc,argv,tbdic); setproginfo ("bolixod",VERSION,MSG_U(I_BOLIXOD,"Manage public information for all Bolixo nodes")); setgrouparg (MSG_U(I_NETWORKING,"Networking")); setarg ('c',"control",MSG_U(I_BOLIXOD_CONTROL,"Unix socket for bolixod"),glocal.control,false); setarg ('p',"clientport",MSG_U(I_CLIENTPORT,"Number suffix to Unix socket"),glocal.clientport,false); setarg (' ',"sessport",MSG_R(O_SESSPORT),glocal.sessport,false); setarg (' ',"mysecret",MSG_R(O_MYSECRET),glocal.mysecret,true); setgrouparg (MSG_U(I_DATABASE,"Database")); setarg (' ',"dbserv",MSG_U(I_DBSERV,"Database server"),glocal.dbserv,false); setarg (' ',"dbname",MSG_U(I_DBNAME,"Database name"),glocal.dbname,false); setarg (' ',"dbuser",MSG_U(I_DBUSER,"Database user"),glocal.dbuser,true); setgrouparg (MSG_U(I_MISC,"Misc.")); setarg (' ',"client_secrets",MSG_R(O_CLIENTSECRETS),glocal.client_secretfile,false); setarg (' ',"user",MSG_U(I_RUNASUSER,"Run the program as this user"),glocal.user,false); setarg (' ',"daemon",MSG_U(I_RUNBG,"Run in background"),glocal.daemon,false); setarg (' ',"pidfile",MSG_U(I_PIDFILE,"File holding the PID of the process"),glocal.pidfile,false); setarg (' ',"domain",MSG_U(O_DOMAIN,"Accept nodes only from this domain"),glocal.domain,false); setarg (' ',"maxaccts",MSG_U(O_MAXACCOUNTSPER,"Maximum accounts per servers"),glocal.maxaccts,false); setarg (' ',"devmode",MSG_U(O_DEVMODE,"Relax rule for registernode API"),glocal.devmode,false); setarg (' ',"nonstrict",MSG_R(O_NONSTRICT),nonstrict,false); if (glocal.daemon){ syslog (LOG_ERR,"%s",msg); }else{ fprintf (stderr,"%s",msg); } if (glocal.daemon){ syslog (LOG_WARNING,"%s",msg); }else{ fprintf (stderr,"%s",msg); } int ret = -1; glocal unsigned nbrequest=0; glocal CONNECT_INFO con_sess; glocal map client_secrets; glocal string controlport = string_f("unix:%s",glocal.control); glocal pid_t pid = (pid_t)-1; glocal string unixportclient = string_f("unix:/tmp/bolixod-client-%u.sock",glocal.clientport); glocal.con_sess.port = glocal.sessport; glocal.con_sess.secret = glocal.mysecret; const char *passwd = getenv("BOLIXOD_PWD"); if (passwd == NULL){ tlmp_error (MSG_U(E_DBPASS,"Can't get database password from environment, aborting\n")); exit (-1); } fdpass_readsecrets (glocal.client_secretfile,glocal.client_secrets); query_setdefaultdb (glocal.dbserv,glocal.dbname,glocal.dbuser,passwd); query_getdefaultdb()->showerrormode(true); ("0.0.0.0",glocal.unixportclient,5); HANDLE_INFO *n = new HANDLE_INFO; info.data = n; if (glocal.unixportclient == info.port){ n->req.secret = fdpass_findsecret (glocal.client_secrets,info.port); if (n->req.secret.size() > 0){ n->type = TYPE_CLIENT; }else{ tlmp_error ("Rejected client connexion from port %s\n",info.port); endclient = true; } }else if (string_cmp(info.port,glocal.controlport)==0){ n->type = TYPE_CONTROL; } debug_printf (D_PROTO,"receive line: %s\n",line); HANDLE_INFO *c = (HANDLE_INFO*)info.data; static const char *tbtype[]={"none","control request","client request"}; ERROR_PREFIX prefix ("%s:",tbtype[c->type]); if (c->type == TYPE_CONTROL){ (this,c->req,line, info.linelen,endserver, endclient, no,c); vector tb; tb.push_back(string_f ("Version: %s",VERSION)); tb.push_back(string_f ("maxaccts: %u",glocal.maxaccts)); tb.push_back(string_f ("nbrequest: %u",glocal.nbrequest)); tb.push_back(string_f ("devmode: %d",glocal.devmode)); tb.push_back(string_f("nonstrict: %d",nonstrict)); instrument_status(tb); rep_status(tb); toggle_instrument_file(on); endserver = true; glocal string msg; ("select nodeid from nodes where nodename='%s'",nodename); glocal.msg = "Nodename not found"; if (sql_action("delete from nodes where nodeid=%s",row[0])==-1){ glocal.msg = "Internal error, can't delete node"; }else if (sql_action("delete from emails where nodeid=%s",row[0])==-1){ glocal.msg = "Internal error, can't delete emails for this node"; } if (glocal.msg.size() > 0){ rep_deletenode (false,glocal.msg); }else{ rep_deletenode (true,""); } if (on){ debug_seton(); }else{ debug_setoff(); } debug_setfdebug (filename); string msg; bool sessiond,db,fsok; bolixod_test (glocal.con_sess,msg,sessiond,db,fsok); rep_test(msg,sessiond,db,fsok); tlmp_error ("One error\n"); // connectto port send glocal const char *send = send; glocal vector lines; // We want to test bolixod connectivity to the outside (connectto,port,5); sendf ("%s\r\n",glocal.send); // We send only the first line of the result. It is just a connection test glocal.lines.push_back(line); glocal.lines.push_back("Output truncated"); end = true; glocal.lines.emplace_back(string_f("fail: %s\n",strerror(errno))); rep_help_connect (glocal.lines); tlmp_error ("Control: Invalid command: %s\n",line); endclient = true; }else if (c->type == TYPE_CLIENT){ glocal.nbrequest++; (this,c->req,line, info.linelen,endserver, endclient, no,c); // Register a new node // nodename glocal string msg; glocal const char *nodename = nodename; if (!glocal.devmode && strncasecmp(nodename,"https://",8) != 0){ glocal.msg = "Invalid nodename, only https node accepted"; }else if (bolixod_validnode (nodename,glocal.domain) == -1){ glocal.msg = "Invalid nodename"; }else{ ("select pub_key from nodes where nodename='%s'",nodename); if (row[0] == NULL){ bolixod_getpubkey (glocal.nodename,glocal.msg); }else{ glocal.msg = "Already registered"; } if (sql_action("insert into nodes (nodename) value ('%s')",glocal.nodename)==-1){ glocal.msg = "Internal error (nodes table)"; }else{ bolixod_getpubkey (glocal.nodename,glocal.msg); } } if (glocal.msg.size() > 0){ rep_registernode(false,glocal.msg); }else{ rep_registernode (true,""); } // nodename glocal const char *nodename = nodename; glocal string msg; glocal string sessionid; ("select pub_key from nodes where nodename='%s'",nodename); if (row[0] != NULL){ glocal.sessionid = fs_makeid (); (glocal.con_sess,glocal.sessionid.c_str()); if (internal_error){ glocal.msg = "Internal error"; }else{ // We are reusing the same session manager as the nodes. // We preserve the nodename. userid==1 means not logged yet. (glocal.con_sess,glocal.sessionid ,1,glocal.nodename,"","","",false,0,""); if (internal_error){ glocal.msg = "Internal error"; } } }else{ glocal.msg = "No public key for the node"; } glocal.msg = "Node not registered"; if (glocal.msg.size() > 0){ rep_nodelogin(false,glocal.msg,""); }else{ rep_nodelogin(true,"",glocal.sessionid); } // session sign glocal string msg; glocal const char *session = session; glocal const char *sign = sign; glocal string nodename; int state = bolixod_sessionstate(glocal.con_sess,session,1,glocal.nodename,glocal.msg); if (state == 1){ ("select pub_key from nodes where nodename='%s'",glocal.nodename.c_str()); if (row[0] == NULL){ glocal.msg = MSG_R(E_NOPUBKEY); }else{ EVP_PKEY *p = fs_load_public (row[0]); if (p != NULL){ string sig = glocal.sign; strip_end (sig); if (fs_verify(glocal.session,p,sig)==-1){ glocal.msg = MSG_R(E_SIGNOMATCH); }else{ // We switch userid to 2, it means login completed (glocal.con_sess,glocal.session ,2,glocal.nodename,"","","",false,0,""); if (internal_error){ glocal.msg = "Internal error"; } } fs_free_public (p); } } glocal.msg = "Internal error reading public key"; } if (glocal.msg.size() > 0){ (glocal.con_sess,session); rep_nodepass(false,glocal.msg); }else{ rep_nodepass(true,""); } // session glocal string msg; (glocal.con_sess,session); if (internal_error){ glocal.msg = "nodelogout failed"; } if (glocal.msg.size() > 0){ rep_nodelogout(false,glocal.msg); }else{ rep_nodelogout(true,""); } // session info // &USERINFO fullname address1 address2 city zipcode state country email phone fax interest glocal const USERINFO_receive *info = &info; glocal const char *user = info.user; glocal string msg; glocal string nodename; int state = bolixod_sessionstate(glocal.con_sess,session,2,glocal.nodename,glocal.msg); if (state == 2){ ("select nodes.nodeid,userid from nodes" " left join users on users.nodeid=nodes.nodeid and users.name='%s'" " where nodes.nodename='%s'",glocal.user,glocal.nodename.c_str()); if (row[1] == NULL){ if (sql_action("insert into users (nodeid,name,fullname,address1,address2,city,state,country" " ,zipcode,email,phone,fax,bolixosite,website,interest)" " value (%s,'%s','%s','%s','%s','%s','%s','%s','%s','%s','%s','%s','%s','%s','%s')" ,row[0],glocal.user ,glocal.info->fullname ,glocal.info->address1 ,glocal.info->address2 ,glocal.info->city ,glocal.info->state ,glocal.info->country ,glocal.info->zipcode ,glocal.info->email ,glocal.info->phone ,glocal.info->fax ,glocal.info->bolixosite ,glocal.info->website ,glocal.info->interest )==-1){ glocal.msg = "Internal error, insert in table"; } }else{ if (sql_action("update users" " set fullname='%s',address1='%s',address2='%s',city='%s',state='%s',country='%s'" " ,zipcode='%s',email='%s',phone='%s',fax='%s'" " ,bolixosite='%s',website='%s',interest='%s'" " where userid=%s" ,glocal.info->fullname ,glocal.info->address1 ,glocal.info->address2 ,glocal.info->city ,glocal.info->state ,glocal.info->country ,glocal.info->zipcode ,glocal.info->email ,glocal.info->phone ,glocal.info->fax ,glocal.info->bolixosite ,glocal.info->website ,glocal.info->interest ,row[1])==-1){ glocal.msg = "Internal error, updating table"; } } // Copy or remove the photos string dir = bolixod_getnodedir(glocal.nodename); mkdir (dir.c_str(),0755); string tmp = string_f("%s/%s-photo.jpg",dir.c_str(),glocal.user); bolixod_updatephoto (tmp,glocal.info->photo); tmp = string_f("%s/%s-mini-photo.jpg",dir.c_str(),glocal.user); bolixod_updatephoto (tmp,glocal.info->mini_photo); glocal.msg = "Node not found"; } if (glocal.msg.size() > 0){ rep_publish(false,glocal.msg); }else{ rep_publish(true,""); } // session info // &USERINFO_V2 fullname address1 address2 city zipcode state country email phone fax interest glocal info; glocal const char *user = info.user; glocal string msg; glocal string nodename; int state = bolixod_sessionstate(glocal.con_sess,session,2,glocal.nodename,glocal.msg); if (state == 2){ ("select nodes.nodeid,userid from nodes" " left join users on users.nodeid=nodes.nodeid and users.name='%s'" " where nodes.nodename='%s'",glocal.user,glocal.nodename.c_str()); if (row[1] == NULL){ if (sql_action("insert into users (nodeid,name,fullname,address1,address2,city,state,country" " ,zipcode,email,phone,fax,bolixosite,website,interest)" " value (%s,'%s','%s','%s','%s','%s','%s','%s','%s','%s','%s','%s','%s','%s','%s')" ,row[0],glocal.user ,glocal.info.fullname ,glocal.info.address1 ,glocal.info.address2 ,glocal.info.city ,glocal.info.state ,glocal.info.country ,glocal.info.zipcode ,glocal.info.email ,glocal.info.phone ,glocal.info.fax ,glocal.info.bolixosite ,glocal.info.website ,glocal.info.interest )==-1){ glocal.msg = "Internal error, insert in table"; } }else{ if (sql_action("update users" " set fullname='%s',address1='%s',address2='%s',city='%s',state='%s',country='%s'" " ,zipcode='%s',email='%s',phone='%s',fax='%s'" " ,bolixosite='%s',website='%s',interest='%s'" " where userid=%s" ,glocal.info.fullname ,glocal.info.address1 ,glocal.info.address2 ,glocal.info.city ,glocal.info.state ,glocal.info.country ,glocal.info.zipcode ,glocal.info.email ,glocal.info.phone ,glocal.info.fax ,glocal.info.bolixosite ,glocal.info.website ,glocal.info.interest ,row[1])==-1){ glocal.msg = "Internal error, updating table"; } } // Copy or remove the photos string dir = bolixod_getnodedir(glocal.nodename); mkdir (dir.c_str(),0755); string tmp = string_f("%s/%s-photo.jpg",dir.c_str(),glocal.user); if (glocal.info.remove_photo) unlink (tmp.c_str()); //bolixod_updatephoto (tmp,glocal.info->photo); tmp = string_f("%s/%s-mini-photo.jpg",dir.c_str(),glocal.user); if (glocal.info.remove_mini_photo) unlink (tmp.c_str()); //bolixod_updatephoto (tmp,glocal.info->mini_photo); glocal.msg = "Node not found"; } if (glocal.msg.size() > 0){ rep_publish(false,glocal.msg); }else{ rep_publish(true,""); } // session user name content:o more:b append:b glocal string msg; glocal string nodename; int state = bolixod_sessionstate(glocal.con_sess,session,2,glocal.nodename,glocal.msg); if (state == 2 && is_any_of(name,"photo.jpg","mini-photo.jpg")){ string dir = bolixod_getnodedir(glocal.nodename); mkdir (dir.c_str(),0755); string path = string_f("%s/%s-%s",dir.c_str(),user,name); string path_new = path + "-new"; FILE *fout = fopen (path_new.c_str(),append ? "a" : "w"); if (fout == nullptr){ tlmp_error ("publish_file: can't open file %s (%s)",path_new.c_str(),strerror(errno)); glocal.msg = "Can't open photo file"; }else{ fwrite (content.getbuffer(),1,content.getsize(),fout); fclose (fout); if (!more){ if (rename (path_new.c_str(),path.c_str())==-1){ tlmp_error ("publish_file rename failed: %s",strerror(errno)); glocal.msg = "internal error, renaming"; } } } } if (glocal.msg.size() > 0){ rep_publish_file (false,glocal.msg); }else{ rep_publish_file (true,""); } // session user string msg; string nodename; int state = bolixod_sessionstate(glocal.con_sess,session,2,nodename,msg); if (state == 2){ if (sql_action("delete users from users join nodes on users.nodeid=nodes.nodeid" " where users.name='%s' and nodes.nodename='%s'",user,nodename.c_str())==-1){ msg = "Internal error, deleting entry"; }else{ // Deletes the photos string dir = bolixod_getnodedir(nodename); string tmp = string_f("%s/%s-photo.jpg",dir.c_str(),user); unlink (tmp.c_str()); tmp = string_f("%s/%s-mini-photo.jpg",dir.c_str(),user); unlink (tmp.c_str()); } } if (msg.size() > 0){ rep_remove(false,msg); }else{ rep_remove(true,""); } // filter:U{FILTER} offset:u nb:u = success:b msg users:v glocal vector users; NSQL_REQ query; query.append ("select name,fullname" ",address1,address2,city,state,country" ",zipcode,email,phone,fax,bolixosite,website,interest,nodename" " from users join nodes on nodes.nodeid=users.nodeid" " where "); auto start_size = query.size(); static const char *sepand = " and "; const char *sep = ""; if (filter.user[0] != '\0'){ query.appendf ("name like '%%%s%%'",filter.user); sep = sepand; } if (filter.fullname[0] != '\0'){ query.appendf("%sfullname like '%%%s%%'",sep,filter.fullname); sep = sepand; } if (filter.address[0] != '\0'){ query.appendf("%s(address1 like '%%%s%%' or address2 like '%%%s%%')" ,sep,filter.address,filter.address); sep = sepand; } if (filter.city[0] != '\0'){ query.appendf("%scity like '%%%s%%'",sep,filter.city); sep = sepand; } if (filter.state[0] != '\0'){ query.appendf("%sstate like '%%%s%%'",sep,filter.state); sep = sepand; } if (filter.country[0] != '\0'){ query.appendf("%scountry like '%%%s%%'",sep,filter.country); sep = sepand; } if (filter.interest[0] != '\0'){ query.appendf("%sinterest like '%%%s%%'",sep,filter.interest); } if (query.size() == start_size){ rep_pub_search (false,"No filter specified",glocal.users); }else{ query.appendf (" order by name,nodename limit %u,%u",offset,nb); (query); USERPUBINFO info; info.user = row[0]; info.fullname = row[1]; info.address1 = row[2]; info.address2 = row[3]; info.city = row[4]; info.state = row[5]; info.country = row[6]; info.zipcode = row[7]; info.email = row[8]; info.phone = row[9]; info.fax = row[10]; info.bolixosite = row[11]; info.website = row[12]; info.interest = row[13]; info.nodename = row[14]; bolixod_setphotos (info); glocal.users.push_back(info); rep_pub_search (true,"",glocal.users); } // filter:U{FILTER} offset:u nb:u = success:b msg users:v glocal vector users; NSQL_REQ query; query.append ("select name,fullname" ",address1,address2,city,state,country" ",zipcode,email,phone,fax,bolixosite,website,interest,nodename" " from users join nodes on nodes.nodeid=users.nodeid" " where "); auto start_size = query.size(); static const char *sepand = " and "; const char *sep = ""; if (filter.user[0] != '\0'){ query.appendf ("name like '%%%s%%'",filter.user); sep = sepand; } if (filter.fullname[0] != '\0'){ query.appendf("%sfullname like '%%%s%%'",sep,filter.fullname); sep = sepand; } if (filter.address[0] != '\0'){ query.appendf("%s(address1 like '%%%s%%' or address2 like '%%%s%%')" ,sep,filter.address,filter.address); sep = sepand; } if (filter.city[0] != '\0'){ query.appendf("%scity like '%%%s%%'",sep,filter.city); sep = sepand; } if (filter.state[0] != '\0'){ query.appendf("%sstate like '%%%s%%'",sep,filter.state); sep = sepand; } if (filter.country[0] != '\0'){ query.appendf("%scountry like '%%%s%%'",sep,filter.country); sep = sepand; } if (filter.interest[0] != '\0'){ query.appendf("%sinterest like '%%%s%%'",sep,filter.interest); } if (query.size() == start_size){ rep_pub_search_v2 (false,"No filter specified",glocal.users); }else{ query.appendf (" order by name,nodename limit %u,%u",offset,nb); (query); USERPUBINFO_V2 info; info.user = row[0]; info.fullname = row[1]; info.address1 = row[2]; info.address2 = row[3]; info.city = row[4]; info.state = row[5]; info.country = row[6]; info.zipcode = row[7]; info.email = row[8]; info.phone = row[9]; info.fax = row[10]; info.bolixosite = row[11]; info.website = row[12]; info.interest = row[13]; info.nodename = row[14]; bolixod_setphotos (info); glocal.users.push_back(info); rep_pub_search_v2 (true,"",glocal.users); } // prefix offset:u nb:u = success:b msg users:v glocal vector users; ("select users.name,fullname" ",address1,address2,city,state,country" ",zipcode,email,phone,fax,bolixosite,website,interest" ",nodes.nodename" " from users join nodes on nodes.nodeid=users.nodeid" " where name >= '%s' order by name limit %u,%u",prefix,offset,nb); USERPUBINFO info; info.user = row[0]; info.fullname = row[1]; info.address1 = row[2]; info.address2 = row[3]; info.city = row[4]; info.state = row[5]; info.country = row[6]; info.zipcode = row[7]; info.email = row[8]; info.phone = row[9]; info.fax = row[10]; info.bolixosite = row[11]; info.website = row[12]; info.interest = row[13]; info.nodename = row[14]; bolixod_setphotos (info); glocal.users.push_back(info); rep_pub_list (true,"",glocal.users); // node user file offset:u = success:b msg modified content:o more:b bool more = false; string msg; BOB_TYPE content; string modified; unsigned size = 0; if (bolixod_validnode(node)==-1){ msg = "Invalid node name"; }else if (bolixod_validfile(user)==-1){ msg = "Invalid user"; }else if (bolixod_validfile(user)==-1){ msg = "Invalid file"; }else{ string dir = bolixod_getnodedir(node); string path = string_f("%s/%s-%s",dir.c_str(),user,file); FILE *fin = fopen(path.c_str(),"r"); struct stat64 st; if (fin == NULL){ msg = "Internal error opening file"; tlmp_error ("readfile_v2: Can't open file %s (%s)\n",path.c_str(),strerror(errno)); }else if (fstat64(fileno(fin),&st)==-1){ msg = "Internal error getting file stats"; tlmp_error ("Can't stat file %s (%s)\n",path.c_str(),strerror(errno)); }else if (offset > st.st_size){ msg = "Offset out of range"; tlmp_error ("readfile_v2: offset out of range for file %s",path.c_str()); }else if (offset != 0 && fseek (fin,offset,SEEK_SET)==-1){ msg = "Can't seek"; tlmp_error ("readfile_v2: Can't seek to position %u for file %s (%s)\n",offset,path.c_str(),strerror(errno)); }else{ size = st.st_size; char buf[REQ_CONTENT_CHUNK]; int len = fread(buf,1,sizeof(buf),fin); if (len > 0){ struct tm *t = localtime(&st.st_mtime); modified = string_f("%04d/%02d/%02d %2d:%2d:%2d" ,t->tm_year+1900,t->tm_mon+1,t->tm_mday ,t->tm_hour,t->tm_min,t->tm_sec); content.setbuffer(buf,len,true); more = st.st_size > offset + len; }else{ msg = "Internal error reading file"; tlmp_error ("Error reading file %s (%s)\n",path.c_str(),strerror(errno)); } fclose (fin); } } if (msg.size() > 0){ content.clear(); rep_readfile_v2(false,msg,"",content,false,0); }else{ rep_readfile_v2(true,"",modified,content,more,size); } // node user file = success:b msg modified content:o string msg; BOB_TYPE content; string modified; if (bolixod_validnode(node)==-1){ msg = "Invalid node name"; }else if (bolixod_validfile(user)==-1){ msg = "Invalid user"; }else if (bolixod_validfile(user)==-1){ msg = "Invalid file"; }else{ string dir = bolixod_getnodedir(node); string path = string_f("%s/%s-%s",dir.c_str(),user,file); FILE *fin = fopen(path.c_str(),"r"); if (fin == NULL){ msg = "Internal error opening file"; tlmp_error ("Can't open file %s (%s)\n",path.c_str(),strerror(errno)); }else{ char buf[REQ_CONTENT_CHUNK]; int len = fread(buf,1,sizeof(buf),fin); if (len > 0){ struct stat st; if (fstat(fileno(fin),&st)!=-1){ struct tm *t = localtime(&st.st_mtime); modified = string_f("%04d/%02d/%02d %2d:%2d:%2d" ,t->tm_year+1900,t->tm_mon+1,t->tm_mday ,t->tm_hour,t->tm_min,t->tm_sec); } content.setbuffer(buf,len,true); }else{ msg = "Internal error reading file"; tlmp_error ("Error reading file %s (%s)\n",path.c_str(),strerror(errno)); } fclose (fin); } } if (msg.size() > 0){ content.clear(); rep_readfile(false,msg,"",content); }else{ rep_readfile(true,"",modified,content); } // session email userid = success:b msg glocal const char *email = email; glocal const char *userid = userid; glocal string msg; glocal string nodename; int state = bolixod_sessionstate(glocal.con_sess,session,2,glocal.nodename,glocal.msg); if (state == 2){ ("select nodeid from nodes where nodename='%s'",glocal.nodename.c_str()); glocal.msg = "Unknown node"; glocal unsigned nodeid = atoi(row[0]); ("select 1 from emails where nodeid=%u and email='%s'" ,glocal.nodeid,glocal.email); // Already there, ok if (sql_action("insert into emails (email,userid,nodeid) values ('%s','%s',%u)" ,glocal.email,glocal.userid,glocal.nodeid)==-1){ glocal.msg = "Internal error, emails table"; } // Compute the number of users for this node ("select count(*) from emails where nodeid=%u",glocal.nodeid); if (sql_action("update nodes set nbuser=%s where nodeid=%u",row[0],glocal.nodeid)==-1){ tlmp_error ("Internal error updation user count for nodename %s\n",glocal.nodename.c_str()); } } if (glocal.msg.size() > 0){ rep_recordemail(false,glocal.msg); }else{ rep_recordemail(true,""); } // email = success:b msg nodename glocal string msg; glocal string nodename; ("select nodename from emails" " join nodes on nodes.nodeid=emails.nodeid" " where email='%s'",email); glocal.nodename = row[0]; glocal.msg = "Not found"; if (glocal.msg.size() > 0){ rep_getnode(false,glocal.msg,""); }else{ rep_getnode(true,"",glocal.nodename); } // userid = success:b msg nodename glocal string msg; glocal string nodename; ("select distinct nodes.nodename,nodes.nbuser from nodes" " left join emails on emails.nodeid=nodes.nodeid" " where nodes.nbuser < %u and nodes.nodeid not in (select nodeid from emails where userid='%s')" " order by nodes.nbuser asc limit 1" ,glocal.maxaccts,userid); glocal.nodename = row[0]; glocal.msg = "No node available"; if (glocal.msg.size() > 0){ rep_newacct_findnode(false,"",""); }else{ rep_newacct_findnode(true,"",glocal.nodename); } string msg; bool sessiond,db,fsok; bolixod_test (glocal.con_sess,msg,sessiond,db,fsok); rep_test(msg,sessiond,db,fsok); tlmp_error ("Client: Invalid command: %s\n",line); endclient = true; } bool some_errors = false; if (fdpass_setcontrol(s,glocal.control,glocal.user)==-1){ some_errors = true; } if (!some_errors && s.is_ok()){ chmod (glocal.unixportclient.c_str()+5,0666); s.setrawmode(true); if (glocal.daemon){ daemon_init(glocal.pidfile,glocal.user); } s.loop(); ret = 0; } return ret; return ret; return glocal.ret; }