/* 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 . */ /* This program update databases. It also the only one which can read the users database. This program was copied from the truelies project. This explains the trli_ strings here and there. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "filesystem.h" #include "bolixo.m" #include #define INSTRUMENT_DONOTOPEN #include "instrument.h" #include "helper.h" 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; int no; std::string host; REQUEST_INFO req; HANDLE_INFO(){ no = -1; type = TYPE_NONE; } }; #include "proto/bo-writed_control.protoh" #include "proto/bo-writed_client.protoh" using namespace std; #define bo_sessiond_admin_getsessioninfo_NOTNEED #include "proto/bo-sessiond_admin.protoch" #define bo_keysd_control_setpassphrase_NOTNEED #define bo_keysd_control_quit_NOTNEED #define bo_keysd_control_debug_NOTNEED #define bo_keysd_control_debugfile_NOTNEED #define bo_keysd_control_checkpassphrase_NOTNEED #define bo_keysd_control_runstatus_NOTNEED #include "proto/bo-keysd_control.protoch" #include "proto/bo-log.protoch" #include "proto/publishd_client.protoch" //#include "proto/bo-log-admin.protoch" /* Get the userid associated with the sessionid */ static unsigned trli_getsessionuser (CONNECT_INFO &con, const char *sessionid, string &userid_str, bool &is_admin, bool &is_node) { glocal unsigned userid = 0; glocal string *userid_str = &userid_str; glocal bool is_admin = false; is_node = false; (con,sessionid); if (success){ glocal.userid = userid; (*glocal.userid_str) = userid_str; glocal.is_admin = admin; translat_selectlang (lang); } is_admin = glocal.is_admin; if (glocal.userid == (unsigned)-1){ glocal.userid = 0; // session for nodes, not user is_node = true; } return glocal.userid; } static unsigned trli_getsessionuser (CONNECT_INFO &con, const char *sessionid, bool &is_admin) { bool is_node; string tmp; return trli_getsessionuser (con,sessionid,tmp,is_admin,is_node); } static unsigned trli_getsessionuser (CONNECT_INFO &con, const char *sessionid, string &userid_str) { bool is_admin,is_node; return trli_getsessionuser (con,sessionid,userid_str,is_admin,is_node); } static unsigned trli_getsessionuser (CONNECT_INFO &con, const char *sessionid) { string tmp; bool is_admin,is_node; return trli_getsessionuser (con,sessionid,tmp,is_admin,is_node); } /* Check if a name only use accepted characters Many characters are refused even if they probably do not cause any problems on the system. But names may be used on the command line (using bofs for example), so we avoid some more. */ static bool bo_writed_lex_check(const char *groupname, string &msg, const char special) { bool ret = true; const char *pt = groupname; while (*pt != '\0'){ if (*pt <= ' '){ ret = false; break; }else if (*pt == special || *pt == '@' || *pt == '#' || *pt == ';' || *pt == '"' || *pt == '\'' || *pt == '*' || *pt == '?' || *pt == '%' || *pt == '`'){ ret = false; break; } pt++; } if (ret){ msg = ""; }else{ msg = "Invalid characters in name"; } return ret; } static bool bo_writed_lex_check(const char *name, string &msg) { return bo_writed_lex_check (name,msg,'/'); } static bool bo_writed_group_check(const char *groupname, string &msg) { return bo_writed_lex_check (groupname,msg,'/'); } static bool bo_writed_fname_check(const char *name, string &msg) { return bo_writed_lex_check(name,msg,'\0'); } static const char *nodename = NULL; static string writed_format_mail_newacct(const char *nickname, PARAM_STRING id_str) { return string_f( MSG_U(I_CONFIRMMSG,"Hello!\r\n" "\r\n" "You just created an account using nickname %s on bolixo.org\r\n" "Just click on the link below to confirm the account.\r\n" "\r\n" "%s/index.hc?webstep=10&confirm=%s\r\n" "\r\n" "Thanks for joining!\r\n") ,nickname ,nodename,id_str.ptr); } static int writed_mail_newaccount( const char *mailserver, const char *mailport, const char *mailfrom, const char *nickname, const char *email, PARAM_STRING id_str) { string tmp = writed_format_mail_newacct(nickname,id_str); return fdpass_sendmail (mailserver,mailport,mailfrom,email ,MSG_U(T_ACCTCONFIRM,"Account confirmation on bolixo.org") ,tmp); }; static int bo_writed_findentry (CONNECT_INFO &con, const char *sessionid, const char *name, const char *threshold, ENTRY &entry, bool expect_exist, bool force_admin) { int ret = -1; entry.userid = trli_getsessionuser(con,sessionid,entry.is_admin); if (entry.userid == 0){ entry.msg = "Invalid session"; }else{ if (force_admin) entry.is_admin = true; ret = fs_findentry(name,entry,expect_exist,threshold); } return ret; } static int bo_writed_findentry (CONNECT_INFO &con, const char *sessionid, const char *name, const char *threshold, ENTRY &entry, bool expect_exist) { return bo_writed_findentry (con,sessionid,name,threshold,entry,expect_exist,false); } static int bo_writed_findentry (CONNECT_INFO &con, const char *sessionid, const char *name, ENTRY &entry, bool expect_exist) { return bo_writed_findentry(con,sessionid,name,"",entry,expect_exist); } struct DIRENTRY{ int itemid; std::string modified; ENTRY_TYPE type; DIRENTRY (int _itemid, const char *_modified, ENTRY_TYPE _type){ itemid = _itemid; modified = _modified; type = _type; } DIRENTRY(){ itemid = -1; type = ENTRY_NONE; } }; struct DIR_2_CREATE{ string name; int parent_dirid; int dirid_2_copy; DIR_2_CREATE(PARAM_STRING _name, int _parent_dirid, int _dirid_2_copy){ name = _name.ptr; parent_dirid = _parent_dirid; dirid_2_copy = _dirid_2_copy; } }; static int bo_writed_copydir ( int dirid, // Directory to copy int target_dirid, // parent directory which will receive the new directory const string &dirname, // Name of the directory to create in the target_dirid unsigned userid, string &msg) { int ret = 0; vector todo; // Sub-directories to copy todo.push_back(DIR_2_CREATE(dirname,target_dirid,dirid)); while (todo.size() > 0){ DIR_2_CREATE &d = todo[0]; glocal map res; ("select name,itemid,modified,type from dirs_content where dirid=%d order by eventtime",d.dirid_2_copy); glocal.res[row[0]] = DIRENTRY(atoi(row[1]),row[2],(ENTRY_TYPE)atoi(row[3])); int newdirid = fs_newid (userid,msg); if (newdirid == -1){ ret = -1; break; }else{ if (fs_insert_dir (d.parent_dirid,newdirid,d.name)==-1){ msg = "Internal error (dirs_content table)"; }else{ for (auto &r:glocal.res){ if (bolixo_isdir(r.second.type)){ todo.push_back(DIR_2_CREATE(r.first,newdirid,r.second.itemid)); }else if (bolixo_isfile(r.second.type)){ if (fs_insert_entry (newdirid,r.second.itemid,r.second.modified,r.first,r.second.type)==-1){ msg = "Internal error (dirs_content table)"; ret = -1; todo.clear(); break; } } } } } if (todo.size() > 0) todo.erase (todo.begin()); } return ret; } /* Identify the userid who will perform some group administration. Normally, user are only allowed to work on list they own. But administrator can work on behalf of another user. The parameter "owner" is the other user. For normal user, this parameter is ignored. Return 0 if not a valid userid (sessionid is invalid) */ static unsigned bo_writed_get_group_owner (CONNECT_INFO &con, const char *sessionid, const char *owner, string &username, string &msg, bool &is_admin) { glocal string *username = &username; glocal string *msg = &msg; glocal unsigned userid = trli_getsessionuser (con,sessionid,is_admin); if (is_admin && owner[0] != '\0'){ ("select userid from id2name where name='%s'",owner); glocal.userid = atoi(row[0]); glocal.userid = 0; if (glocal.userid == 0) msg = MSG_U(E_UNKNOWNOWNER,"Unknown owner"); username = owner; is_admin = false; }else if (glocal.userid != 0){ ("select name from id2name where userid=%u",glocal.userid); (*glocal.username) = row[0]; (*glocal.msg) = "Can't find username"; glocal.userid = 0; }else{ msg = "Not logged"; } return glocal.userid; } static unsigned bo_writed_get_group_owner (CONNECT_INFO &con, const char *sessionid, const char *owner, string &username, string &msg) { bool is_admin; return bo_writed_get_group_owner (con,sessionid,owner,username,msg,is_admin); } static unsigned bo_writed_get_group_owner (CONNECT_INFO &con, const char *sessionid, const char *owner, string &msg) { string username; bool is_admin; return bo_writed_get_group_owner (con,sessionid,owner,username,msg,is_admin); } static void bo_writed_set_msgid(string &msgid, const char *replyto) { // replyto may be the original message, or a reply to the original messages // So it may be xxxx or xxxx:yyyy if (replyto != NULL){ const char *pt = strchr(replyto,':'); string tmp; if (pt != NULL){ tmp = string(replyto,pt-replyto); replyto = tmp.c_str(); } msgid = string_f("%s:%s",replyto,msgid.c_str()); } } static string bo_writed_sign (CONNECT_INFO &con_keys, unsigned userid, const BOB_TYPE &content) { glocal string ret; // Sign the message (con_keys,userid,content); if (status == ERR_CODE_NONE){ glocal.ret = sign; }else{ tlmp_error ("Can't sign message: status=%d %s\n",status,msg); } return glocal.ret; } static string bo_writed_sign (CONNECT_INFO &con_keys, unsigned userid, PARAM_STRING content) { return bo_writed_sign (con_keys,userid,BOB_TYPE(content.ptr,strlen(content.ptr),false)); } /* Send a message to a project or reply to a message of a project */ static int bo_writed_project_msg( CONNECT_INFO &con, CONNECT_INFO &con_keys, const char *sessionid, const char *owner, const char *manager, const char *project, const char *role, const char *replyto, // Message ID or NULL const char *title, const char *content, string &msg, string &msgid) { /* We send a message this way -We write the message in the outbox as en ENTRY_FILE -We copy it to destination inbox as ENTRY_MSG Any copy of the message elsewhere will do done as ENTRY_FILE. So when replying to a message ID, we can locate the inbox using a single select */ int ret = -1; msg = "Invalid session"; string username; glocal unsigned userid = bo_writed_get_group_owner (con, sessionid, owner, username,msg); if (glocal.userid != 0){ int ownerid = fs_rec_getid ("select userid from id2name where name='%s'",manager); if (ownerid == -1){ msg = "Unkown user"; }else{ vector inboxes; vector listids; fs_list_inboxes(glocal.userid,inboxes,listids,true); int dirid = -1; int listid = -1; msg = "Invalid destination/inbox"; for (unsigned i=0; i static bool bo_writed_remote_user (PARAM_STRING user) { return strchr(user.ptr,'@')!=NULL; } /* Strip our nodename for the user so user@ournode becomes user user stays user user@some_other_node stays user@some_other_node */ static string bo_writed_remove_localnode( const char *user) { string ret; const char *our_node = strstr(nodename,"//"); if (our_node != NULL){ our_node += 2; }else{ tlmp_error ("Can't parse our nodename %s, no //\n",nodename); our_node = ""; } const char *pt = strchr(user,'@'); if (pt == NULL){ ret = user; }else if (strcasecmp(our_node,pt+1)==0){ ret = string(user,pt-user); }else{ ret = user; } return ret; } /* Check that all recipients do exist and are members of the sender contact list. For private site, all local users are accepted. Remote user have to be member of the contact list. admin is always valid. *** private site NOT done */ static int bo_writed_check_recipients( unsigned userid, // All recipients must be member of this user contact group const vector &recipients, vector> &userids, string &msg, bool is_admin) { int ret = -1; if (recipients.size() == 0){ ret = 0; }else{ glocal vector> *r_userids = &userids; /* recipients may be specified with just the nickname or nickname@nodename. We remove the nodename when it is this node. */ vector tos; const char *our_node = strstr(nodename,"//"); if (our_node != NULL){ our_node += 2; }else{ tlmp_error ("Can't parse our nodename %s, no //\n",nodename); our_node = ""; } for (auto r:recipients){ if (strcasecmp(r,"admin")==0){ // Everyone is allowed to talk to admin userids.push_back(pair("admin",1)); }else{ const char *pt = strchr(r,'@'); if (pt == NULL){ tos.push_back(r); }else if (strcasecmp(our_node,pt+1)==0){ tos.push_back(string(r,pt-r)); }else{ tos.push_back(r); } } } if (tos.size() > 0){ NSQL_REQ req; if (is_admin){ // No membership needed. Admin can talk to anyone req.append("select id2name.name,id2name.userid from id2name where ("); }else{ req.appendf("select id2name.name,id2name.userid from groups" " join group_members on group_members.groupid = groups.id" " join id2name on id2name.userid=group_members.userid" " where groups.name='contacts' and groups.ownerid=%u and (",userid); } const char *sep = ""; for (auto &r:tos){ req.appendf(" %s id2name.name='%s'",sep,r.c_str()); sep = "or"; } req.append (")"); (req); glocal.r_userids->push_back(pair(row[0],atoi(row[1]))); } if (userids.size() != recipients.size()){ msg = MSG_U(E_BADDEST,"Some recipient(s) invalid:"); for (auto r:recipients){ bool found = false; for (auto &i:userids){ if (strcmp(r,i.first.c_str())==0){ found = true; break; } } if (!found) msg += string(" ") + r; } }else{ ret = 0; } } return ret; } static void bo_writed_sendmsg ( CONNECT_INFO &con, CONNECT_INFO &con_keys, const char *sessionid, const char *owner, const vector &recipients, const char *replyto, // Message ID or NULL const char *title, const char *content, string &msg, string &msgid) { msg = "Invalid session"; string username; glocal unsigned userid = bo_writed_get_group_owner (con, sessionid, owner, username, msg); if (recipients.size() == 0){ msg = MSG_U(E_NORECIPIENT,"No recipient specified"); }else if (glocal.userid != 0){ // Check that all recipients do exist glocal vector> r_userids; if (bo_writed_check_recipients(glocal.userid,recipients,glocal.r_userids,msg,false)!=-1){ msg = ""; if (replyto != NULL){ int inbox_id = fs_find_inbox(glocal.userid,username,false,msg); if (inbox_id == -1 || fs_rec_getid ("select itemid from dirs_content where dirid=%d and name='%s'" ,inbox_id,replyto)==-1){ msg = MSG_U(E_UNKNOWNMSG,"replyto: Unknown message"); } } if (msg.size() == 0){ int outbox_id = fs_find_outbox(glocal.userid,username,msg); if (outbox_id != -1){ string sign = bo_writed_sign (con_keys,glocal.userid,content); // All messages are member of group #all, with listmode='r' // But access is controlled by the parent directory int fileid = fs_newid (glocal.userid,0,'r',msg,msgid); if (fileid != -1){ DATEASC now; fs_set_now(now); bo_writed_set_msgid (msgid,replyto); if (fs_insert_file(outbox_id,fileid,now.buf,msgid)==-1){ msg = "Internal error (dirs_content table)"; }else if (sql_action("insert into files (id,modified,filetype,title,content,signature)" " values (%d,'%s',%u,'%s','%s','%s')" ,fileid,now.buf,FILE_TEXT,title,content,sign.c_str())==-1){ msg = "Internal error (files table)"; }else{ for (unsigned i=0; i static bool bo_writed_is_text (const BOB_TYPE &content) { bool ret = true; const unsigned char *pt = (const unsigned char*) content.getbuffer(); for (unsigned i=0; i= 3){ unsigned size = content.getsize(); const unsigned char *buf = (const unsigned char*) content.getbuffer(); //tlmp_error ("%02x %02x %02x\n",buf[0],buf[1],buf[2]); if (size > 3 && buf[0] == 0x49 && buf[1] == 0x44 && buf[2] == 0x33){ // mp3 file_type = FILE_SOUND_MP3; }else if (size > 4 && buf[0] == 0x4F && buf[1] == 0x67 && buf[2] == 0x67 && buf[3] == 0x53){ // ogg file_type = FILE_SOUND_OGG; }else if (size > 4 && buf[0] == 0xFF && buf[1] == 0xD8 && buf[2] == 0xFF && buf[3] == 0xDB){ // jpeg file_type = FILE_IMAGE_JPG; }else if (size > 12 && buf[0] == 0xFF && buf[1] == 0xD8 && buf[2] == 0xFF && buf[3] == 0xE1 && buf[6] == 0x45 && buf[7] == 0x78 && buf[8] == 0x69 && buf[9] == 0x66 && buf[10] == 0x00 && buf[11] == 0x00){ // jpeg file_type = FILE_IMAGE_JPG; }else if (size > 12 && buf[0] == 0xFF && buf[1] == 0xD8 && buf[2] == 0xFF && buf[3] == 0xE0 && buf[6] == 0x4A && buf[7] == 0x46 && buf[8] == 0x49 && buf[9] == 0x46 && buf[10] == 0x00 && buf[11] == 0x01){ // jpeg file_type = FILE_IMAGE_JPG; }else if (size > 6 && buf[0] == 0x47 && buf[1] == 0x49 && buf[2] == 0x46 && buf[3] == 0x38 && (buf[4] == 0x37 || buf[4] == 0x39) && buf[5] == 0x61){ file_type = FILE_IMAGE_GIF; }else if (size > 8 && buf[0] == 0x89 && buf[1] == 0x50 && buf[2] == 0x4E && buf[3] == 0x47 && buf[4] == 0x0D && buf[5] == 0x0A && buf[6] == 0x1A && buf[7] == 0x0A){ file_type = FILE_IMAGE_PNG; }else if (size > 8 && buf[0] == 0x00 && buf[1] == 0x00 && buf[2] == 0x00 && buf[3] == 0x18 && buf[4] == 0x66 && buf[5] == 0x74 && buf[6] == 0x79 && buf[7] == 0x70){ // && buf[8] == 0x33 && buf[9] == 0x67 && buf[10] == 0x70 //&& buf[11] == 0x35){ file_type = FILE_VIDEO; }else{ // Check if this is a text if (bo_writed_is_text(content)) file_type = FILE_TEXT; } }else{ if (bo_writed_is_text(content)) file_type = FILE_TEXT; } if (file_type == FILE_UNKNOWN){ const char *ext = strrchr(name.ptr,'.'); if (ext != NULL){ if (strcasecmp(ext,".mp3")==0 || strcasecmp(ext,".wav")==0 || strcasecmp(ext,".ogg")==0){ file_type = FILE_SOUND_MP3; }else if (strcasecmp(ext,".mp4")==0){ file_type = FILE_VIDEO; }else if (strcasecmp(ext,".gif")==0){ file_type = FILE_IMAGE_GIF; }else if (strcasecmp(ext,".jpeg")==0 || strcasecmp(ext,".jpg")==0){ file_type = FILE_IMAGE_JPG; }else if (strcasecmp(ext,".png")==0){ file_type = FILE_IMAGE_PNG; } } } return file_type; } /* Update the modification date of a directory */ static void bo_writed_update_dirdate(unsigned dirid) { if (sql_action("update dirs_content set modified=now() where itemid=%u",dirid)==-1){ tlmp_error (MSG_U(E_CANTUPDDATEDIR,"Can't update directory modification date\n")); } } struct ADDFILE_INFO{ FILE_TYPE file_type=FILE_UNKNOWN; string fileuuid; string handle; int fileid=0; DATEASC modified; }; static int bo_writed_addfile_bob ( CONNECT_INFO &con_keys, const char *sessionid, PARAM_STRING name, ENTRY_TYPE type, int dirid, unsigned userid, const BOB_TYPE &content, bool more, string &sign, // Either contain the Pre-signed content or will contain the new signature ADDFILE_INFO &info, string &msg) { info.fileid = fs_newid (userid,0,'r',msg,info.fileuuid); if (info.fileid != -1){ const char *basename = name.ptr; if (basename == NULL) basename = info.fileuuid.c_str(); fs_set_now(info.modified); info.file_type = bo_writed_file_type (basename,content,more); const char *content_str = NULL; string tmp; if (!more){ if (info.file_type == FILE_TEXT){ tmp = string((const char *) content.getbuffer(),content.getsize()); content_str = tmp.c_str(); } if (sign.size() > 0){ // Already signed, validate glocal string pubkey; ("select pub_key from id2name where userid=%u",userid); if (row[0] != NULL) glocal.pubkey = row[0]; if (glocal.pubkey.size()==0){ msg = string_f("No public key for userid=%u",userid); tlmp_error ("%s\n",msg.c_str()); }else if (fs_verify(glocal.pubkey,content,sign)==-1){ msg = string_f ("Signature do not match for pre-signed file %s",basename); tlmp_error ("%s\n",msg.c_str()); } }else{ sign = bo_writed_sign (con_keys,userid,content); } } if (msg.size()==0){ if (fs_insert_entry(dirid,info.fileid,info.modified.buf,basename,type)==-1){ msg = "Internal error (dirs_files table)"; }else if (sql_action("insert into files (id,modified,filetype,content,signature) values (%d,'%s',%u,'%s','%s')" ,info.fileid,info.modified.buf,info.file_type,content_str,sign.c_str())==-1){ msg = "Internal error (files table)"; }else{ if (content_str == NULL){ FILE *fout = fs_alloc_file_handle (info.fileid,info.modified.buf,"w",info.handle,sessionid); if (fout == NULL){ tlmp_error ("Can't open file (%s)\n",strerror(errno)); msg = "Internal error (1-writing data)"; }else{ size_t size = content.getsize(); if (fwrite (content.getbuffer(),1,size,fout)!=size){ msg = "Internal error (2-writing data)"; }else{ msg.clear(); } } } bo_writed_update_dirdate(dirid); } } } return info.fileid; } /* Create the directory for a project */ static int bo_writed_create_project_dir ( unsigned userid, PARAM_STRING username, PARAM_STRING listname, string &msg) { int ret = -1; int listid = fs_rec_getid ("select id from group_lists where ownerid=%u and name='%s'" ,userid,listname.ptr); if (listid == -1){ msg = "List does not exist"; }else{ vector dirs = {"projects",username.ptr,listname.ptr}; vector listids = {0,0,(unsigned)listid}; vector listmodes = {'p','p','w'}; bool may_add; msg = ""; ret = fs_locate_dir (dirs,userid,true,msg,END_OF_TIME,may_add,true,&listids,&listmodes); } return ret; } /* Create a group_list for a user */ static int bo_writed_create_group_list(unsigned userid, const char *listname, const char *description) { return sql_action("insert into group_lists (ownerid,name,description) values (%u,'%s','%s')",userid,listname,description); } /* Create a group_list for the user and the associated project directory */ static int bo_writed_create_group_list(unsigned userid, PARAM_STRING username, const char *listname, const char *description, string &msg) { int ret = bo_writed_create_group_list (userid,listname,description); if (ret != -1){ ret = bo_writed_create_project_dir (userid,username,listname,msg); } return ret; } static int bo_writed_create_group (unsigned userid, const char *groupname, bool create_dash_list, const char *description, string &msg) { glocal int ret = -1; glocal const char *groupname = groupname; glocal string *msg = &msg; glocal unsigned userid = userid; if (sql_action("insert into groups (ownerid,name,description) values (%u,'%s','%s')",userid,groupname,description)==-1){ msg = "Internal error (group_lists table)"; }else{ glocal.ret = query_getdefaultdb()->getlastid(); if (create_dash_list){ glocal.ret = -1; if (sql_action("insert into group_lists (ownerid,name) values (%u,'#%s')" ,userid,groupname)==-1){ msg = "Internal error (group_lists table)"; }else{ ("select id from group_lists where ownerid=%u and name='#%s'" ,userid,groupname); glocal unsigned group_list_id = atoi(row[0]); ("select id from groups where ownerid=%u and name='%s'" ,glocal.userid,glocal.groupname); unsigned groupid = atoi(row[0]); if (sql_action("insert into group_list_members (group_list_id,groupid,defaultaccess) values (%u,%u,'r')" ,glocal.group_list_id,groupid)==-1){ (*glocal.msg) = "Internal error (group_list_members table)"; }else{ glocal.ret = groupid; } } } } return glocal.ret; } /* Add/remove a group into a list */ static void bo_writed_set_group ( unsigned userid, const char *listname, const char *groupname, const char *access, string &msg) { glocal unsigned userid = userid; glocal const char *listname = listname; glocal const char *groupname = groupname; glocal const char *access = access; glocal string *msg = &msg; ("select id from group_lists where ownerid=%u and name='%s'",userid,listname); (*glocal.msg) = string_f(MSG_U(E_PRJNOTEXIST,"Project %s does not exist"),glocal.listname); glocal unsigned group_list_id = atoi(row[0]); ("select id from groups where ownerid=%u and name='%s'",glocal.userid,glocal.groupname); (*glocal.msg) = "Group does not exist"; glocal unsigned groupid = atoi(row[0]); ("select 1 from group_list_members" " where group_list_id=%u and groupid=%u" ,glocal.group_list_id,glocal.groupid); if (glocal.access[0] == '-'){ if (sql_action("delete from group_list_members" " where group_list_id=%u and groupid=%u" ,glocal.group_list_id,glocal.groupid)==-1){ (*glocal.msg) = "Internal error (group_list_members table)"; } }else if (sql_action("update group_list_members set defaultaccess='%s'" " where group_list_id=%u and groupid=%u" ,glocal.access,glocal.group_list_id,glocal.groupid)==-1){ (*glocal.msg) = "Internal error (group_list_members table)"; } if (glocal.access[0] == '-'){ (*glocal.msg) = "Group was not a member of that list"; }else if (sql_action("insert into group_list_members (group_list_id,groupid,defaultaccess) values (%u,%u,'%s')" ,glocal.group_list_id,glocal.groupid,glocal.access)==-1){ (*glocal.msg) = "Internal error (group_list_members table)"; } } /* Add or remove a member from a group */ static void bo_writed_group_member (unsigned userid, const char *groupname, unsigned memberid, const char *access, bool add, string &msg) { int groupid = fs_rec_getid("select id from groups where ownerid=%u and name='%s'",userid,groupname); if (groupid == -1){ msg = string_f("Internal error, can't manage group %s, does not exist",groupname); }else if (add){ if (sql_action ("insert into group_members (groupid,userid,access)" " values (%d,%u,'%s')" ,groupid,memberid,access)==-1){ msg = "Internal error, can't insert into group_members"; } }else{ if (sql_action ("delete from group_members where groupid=%d and userid=%d" ,groupid,memberid)==-1){ msg = "Internal error, can't delete from group_members"; } } } static void bo_writed_update_interest_table(unsigned userid, int dirid) { if (sql_action("update interests set dirid=%d where check_userid=%u",dirid,userid)==-1){ tlmp_error ("Fail to update interests table for %u/%d\n",userid,dirid); } } /* A short inbox was created. If this is the public short inbox, we check if there are users having interest in it. So we update the interests table to place the directory id of the newly create inbox */ static void bo_writed_update_interest( bool created, const char *groupname, unsigned userid, unsigned dirid) { if (created && strcmp(groupname,"public")==0){ glocal unsigned userid = userid; glocal unsigned dirid = dirid; ("select public_view from config where userid=%u",userid); if (atoi(row[0])>0){ bo_writed_update_interest_table (glocal.userid,glocal.dirid); } } } /* Update the interests table. If a user switch the state of public_view, his public short inbox ID will be updated in the interests table. If public_view is false, the ID will be set to -1. */ static void bo_writed_update_interest( bool public_view, unsigned userid, PARAM_STRING username) { int dirid = -1; if (public_view){ string msg; dirid = fs_find_short_inbox (userid,username,"public",msg); } bo_writed_update_interest_table (userid,dirid); } struct CONTEXT { CONNECT_INFO con_keys; // Connection to the bo-keysd server CONNECT_INFO con_publish;// Connection to the publishd server const char *mailserver; const char *mailport; const char *mailfrom; NSQL *usq; bool mailon; // Send confirmation mails (for testing) FILE *flog; CONTEXT(){ mailon = true; mailserver = NULL; mailfrom = NULL; mailport = NULL; usq = NULL; flog = NULL; } }; static void bo_writed_adduser (CONTEXT &ctx, const char *lang, const char *name, const char *email, const char *password, string &id_str, string &msg) { glocal CONTEXT *ctx = &ctx; glocal const char *lang = lang; glocal string msg; glocal string id_str; glocal const char *name = name; glocal const char *email = email; glocal const char *password = password; if (bo_writed_lex_check(name,glocal.msg)){ (*ctx.usq,"select email from users where email='%s'",email); // Email already exist glocal.msg = MSG_U(E_ACCTEXIST,"An account using this email already exists"); (*glocal.ctx->usq,"select name from users where name='%s'",glocal.name); glocal.msg = MSG_U(E_NICKEXIST,"An account already exist using this nickname"); glocal.id_str = fs_makeid (); int action_ret = -1; if (glocal.password == nullptr || glocal.password[0] == '\0'){ action_ret = sql_action(*glocal.ctx->usq,"insert into users (name,email,password,userid_str) values ('%s','%s',NULL,'%s')" ,glocal.name,glocal.email,glocal.id_str.c_str()); }else{ action_ret = sql_action(*glocal.ctx->usq,"insert into users (name,email,password,userid_str) values ('%s','%s',password('%s'),'%s')" ,glocal.name,glocal.email,glocal.password,glocal.id_str.c_str()); } if (action_ret == -1){ glocal.msg = "Internal error: can't create"; }else{ int userid = glocal.ctx->usq->getlastid(); if (sql_action("insert into id2name (userid,name) values (%d,'%s')",userid,glocal.name)==-1){ glocal.msg = "Internal error: can't create2"; }else{ (glocal.ctx->con_keys,glocal.id_str); // Retrieve the password hashed by MySQL (*glocal.ctx->usq,"select password from users where email='%s'",glocal.email); const char *password = row[0] == nullptr ? "" : row[0]; bo_log_adduser (glocal.ctx->flog,glocal.id_str,glocal.name,glocal.email,password,time(NULL)); // Create a record in the config table if (sql_action("insert into config (userid,lang) value (%d,'%s')",userid,glocal.lang)==-1){ glocal.msg = "Can't create3: table config"; } if (glocal.ctx->mailon){ writed_mail_newaccount(glocal.ctx->mailserver,glocal.ctx->mailport,glocal.ctx->mailfrom ,glocal.name,glocal.email,glocal.id_str); } } } } id_str = glocal.id_str; msg = glocal.msg; } static void bo_writed_interest_set(unsigned userid, const char *user, string &msg) { glocal unsigned userid = userid; glocal const char *user = user; glocal string *msg = &msg; glocal int check_id = fs_rec_getid ("select userid from id2name where name='%s'",user); if (glocal.check_id == -1){ *glocal.msg = MSG_U(E_IVLDUSER,"unknown user"); }else{ glocal int dirid; glocal.dirid = fs_find_short_inbox(glocal.check_id,glocal.user,"public",*glocal.msg); if (glocal.dirid == -1){ // No public short inbox for this user. We register the interest // When the short inbox will be created, we will update the interest on the fly. msg.clear(); } if (!bo_writed_remote_user(user)){ // Check the public_view only for local user. If the user has no public_view // we se dirid to -1. It will be changed whenever the user sets his public_view ("select public_view from config where userid=%d",glocal.check_id); if (atoi(row[0]) == 0) glocal.dirid = -1; *glocal.msg = "Internal error, no configuration for user"; glocal.dirid = -1; } if (msg.size()==0){ ("select check_userid from interests where userid=%u and check_userid=%d",glocal.userid,glocal.check_id); if (sql_action("insert into interests (userid,check_userid,dirid,since) values (%u,%d,%d,now())",glocal.userid,glocal.check_id,glocal.dirid)==-1){ *glocal.msg = "Internal error, interests table"; } *glocal.msg = MSG_U(E_ALREADYSET,"Already member of the interest set"); } } } static int bo_writed_set_member (int groupid, const char *groupname, unsigned userid, PARAM_STRING username) { int ret = 0; if (sql_action("insert into group_members (groupid,userid,access,role) values (%u,%u,'W','')" ,groupid,userid)==-1){ tlmp_error ("Internal error setting user %s member of his group %s",username.ptr,groupname); ret = -1; } return ret; } static int bo_writed_confirmuser (CONTEXT &ctx, unsigned userid, PARAM_STRING name, PARAM_STRING confirmid, string &msg) { int ret = -1; if (sql_action(*ctx.usq,"update users set confirmed=now() where userid=%u",userid)!=-1){ ("select lang from config where userid=%u",userid); translat_selectlang(row[0]); bo_log_confirmuser (ctx.flog,confirmid,time(NULL)); ret = 0; /* Create a project named "public" Create a group named "contacts" Make this group member of the project "public" Create a group named "public" Make this group member of project "public" Make this user member of his group "public" Add interest for user admin */ bo_writed_create_group_list(userid,name,"public",MSG_U(I_PUBLICVIEW,"Public view"),msg); bo_writed_create_group (userid,"contacts",false,"",msg); bo_writed_set_group(userid,"public","contacts","R",msg); int groupid = bo_writed_create_group (userid,"public",true,MSG_R(I_PUBLICVIEW),msg); if (groupid != -1){ bo_writed_set_group(userid,"public","public","R",msg); bo_writed_set_member (groupid,"public",userid,name); } bo_writed_interest_set (userid,"admin",msg); groupid = bo_writed_create_group (userid,"inbox",true,MSG_U(I_PRIVINBOX,"Private inbox"),msg); if (groupid != -1){ bo_writed_set_member (groupid,"inbox",userid,name); } groupid = bo_writed_create_group (userid,"anonymous",true,MSG_U(I_PUBLICINBOX,"Public inbox"),msg); if (groupid != -1){ bo_writed_set_member (groupid,"anonymous",userid,name); } }else{ msg = "Error, can't confirm new user"; } return ret; } // Get the information of this session. (Used for node operation) // Return 0 if the expected_state was seen. // Return -1 for any error. static int bod_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{ //tlmp_error ("sessionstate ok expect %d\n",glocal.expected); glocal.ret = 0; *glocal.nodename = userid_str; } return glocal.ret; } /* Send a message to a user from the admin */ static void bo_writed_send_admin_msg ( CONNECT_INFO &con_keys, unsigned userid, PARAM_STRING username, PARAM_STRING message) { bool created; string msg; int dirid = fs_find_short_inbox (userid,username,"inbox",msg,true,created); if (dirid != -1){ int adminid = fs_rec_getid("select userid from id2name where name='admin'"); if (adminid == -1){ tlmp_error ("Can't get admin userid\n"); }else{ ADDFILE_INFO info; BOB_TYPE content(message.ptr,strlen(message.ptr),false); string sign; bo_writed_addfile_bob (con_keys,NULL,NULL,ENTRY_MSG,dirid,adminid ,content,false,sign,info,msg); } } } /* Check if this file is /msgs/some_user/short-inbox/public/... where some_user has enabled public_view in his configuration. If true, anybody can read this file. It overrides all read access. */ static bool bo_writed_public_msg(const char *srcname) { bool ret = false; if (strncmp(srcname,"/msgs/",6)==0){ const char *ptuser = srcname+6; const char *pt = strchr(ptuser,'/'); if (pt != NULL && strncmp(pt,"/short-inbox/public/",20)==0){ string user = string (ptuser,pt-ptuser); bool public_view = fs_rec_getid ("select config.public_view from id2name" " join config on config.userid=id2name.userid" " where id2name.name ='%s'",user.c_str()); if (public_view) ret = true; } } return ret; } /* Send notifications (session manager and email) about an event. It checks the table notifications to filter out some notifications. The notificartions table has this logic. If there is a record for a userid,key, then it applies. If there is no record, then we assume that notification is on for the user interface (ui) and off for email and digest. */ static void bo_writed_notify ( CONTEXT &ctx, CONNECT_INFO &con_sess, PARAM_STRING key, const vector &userids, const string &email_title, const string &email_content) { if (userids.size() > 0){ glocal const char *email_title = email_title.c_str(); glocal const char *email_content = email_content.c_str(); glocal CONTEXT *ctx = &ctx; glocal const char *key = key.ptr; glocal vector userids_ui; // Will collect the userids which should be notified passivly by the UI glocal vector userids_email; // Will collect the userids which should be notified by email glocal set userids_notseen; // At the end, will contain userids not seen in the notifications table // So the default notification is used (passive UI) for (auto u:userids) glocal.userids_notseen.insert(u); NSQL_REQ req; req.append ("select userid,ui,email from notifications where userid in"); req.appendlist(userids); req.appendf (" and notify_key='%s'",key.ptr); (req); unsigned userid = atoi(row[0]); bool ui = atoi(row[1]) != 0; bool email = atoi(row[2]) != 0; if (email) glocal.userids_email.push_back(userid); if (ui) glocal.userids_ui.push_back(userid); glocal.userids_notseen.erase(userid); // Userids not found in the query get the default behavior for (auto u:glocal.userids_notseen) glocal.userids_ui.push_back(u); if (glocal.userids_ui.size() > 0){ (con_sess,glocal.userids_ui,key); } if (glocal.userids_email.size() > 0){ req.clear(); req.append ("select email from users where userid in"); req.appendlist(glocal.userids_email); req.append (" and disabled is null"); (*ctx.usq,req); fdpass_sendmail (glocal.ctx->mailserver,glocal.ctx->mailport,glocal.ctx->mailfrom ,row[0] ,glocal.email_title,glocal.email_content); } } } static void bo_writed_notify ( CONTEXT &ctx, CONNECT_INFO &con_sess, PARAM_STRING key, unsigned userid, const string &email_title, const string &email_content) { vector userids={userid}; bo_writed_notify (ctx,con_sess,key,userids,email_title,email_content); } static void bo_writed_notify_talk_inbox( CONTEXT &ctx, CONNECT_INFO &con_sess, PARAM_STRING user, unsigned userid, const string &email_title, const string &email_content) { string tmp = string_f("talks:%s:inbox",user.ptr); bo_writed_notify(ctx,con_sess,tmp,userid,email_title,email_content); } struct FOLDERITEMS{ unsigned itemid; string modified; string eventtime; FOLDERITEMS(unsigned _itemid, const char *_modified, const char *_eventtime) :itemid(_itemid), modified(_modified), eventtime(_eventtime) {} }; /* Compose the message for an email notification sent for a small message. */ static void bo_writed_set_email_notify ( PARAM_STRING author, PARAM_STRING groupowner, const char *groupname, FILE_TYPE file_type, const BOB_TYPE &content, string &email_title, string &email_content) { if (author.ptr[0] != '\0'){ email_title = string_f(MSG_U(T_EMAILNOTIFYFROM,"There is a new message in group %s/%s from %s") ,groupowner.ptr,groupname,author.ptr); }else{ email_title = string_f(MSG_U(T_EMAILNOTIFY,"There is a new message in group %s/%s") ,groupowner.ptr,groupname); } if (file_type == FILE_TEXT){ email_content = string((const char*)content.getbuffer(),content.getsize()); email_content += string_f("\r\n\r\n%s/index.hc?webstep=9&webtab_add=1:%s:%s" ,nodename,groupowner.ptr,groupname); }else if (file_is_sound(file_type)){ email_content = MSG_U(I_EMAILNOTIFYSOUND,"The author sent a sound file"); }else if (file_is_image(file_type)){ email_content = MSG_U(I_EMAILNOTIFYIMAGE,"The author sent an image"); }else if (file_is_video(file_type)){ email_content = MSG_U(I_EMAILNOTIFYVIDEO,"The author sent a video"); } } int main (int argc, char *argv[]) { glocal int ret = -1; glocal int noproc = 1; glocal const char *secretfile = "/etc/bolixo/secrets.client"; glocal const char *bind = "0.0.0.0"; glocal const char *port = "9100"; glocal const char *control = "/var/run/bo-writed.sock"; glocal const char *user = "bolixo"; glocal const char *logfile = "/var/log/bolixo/bo-writed.log"; glocal const char *data_dbserv = "localhost"; glocal const char *data_dbname = "files"; glocal const char *data_dbuser = NULL; glocal const char *users_dbserv = "localhost"; glocal const char *users_dbname = "users"; glocal const char *users_dbuser = NULL; glocal const char *mysecret = NULL; glocal const char *sessionhost = "127.0.0.4"; glocal const char *sessionport = "9200"; glocal const char *sessionbind = ""; glocal const char *keysdport = "/dev/keysd.sock"; glocal const char *publishdport = "/dev/publishd.sock"; glocal const char *sql_tcpport = NULL; glocal const char *mailserver = "unix:"; glocal const char *mailport = "/dev/smtp.sock"; glocal const char *mailfrom = NULL; glocal bool daemon = false; glocal const char *pidfile = "/var/run/bo-writed.pid"; glocal const char *force_addr = NULL; glocal const char *bob_dir = "/var/lib/bolixo"; glocal bool private_site = false; glocal const char *ftimezones = "/etc/timezones.lst"; static const char *tbdict[]={"bolixo","tlmpsql",NULL}; translat_setlang ("eng,fr"); glocal.ret = (argc,argv,tbdict); setproginfo ("bo-writed",VERSION,"..."); setgrouparg ("Networking"); setarg ('b',"bindaddr","Bind to this address (TCP)",glocal.bind,false); setarg ('p',"tcpport","Listen for command on this TCP port",glocal.port,false); setarg ('c',"control","Unix socket for trlid-control",glocal.control,false); setgrouparg ("Session server"); setarg (' ',"sessionhost","Host running the bo-sessiond server",glocal.sessionhost,false); setarg (' ',"sessionport","Port to reach the bo-sessiond server",glocal.sessionport,false); setarg (' ',"sessionbind","Bind to this IP to talk to bo-sessiond",glocal.sessionbind,false); setarg (' ',"mysecret","Secret used to talk to sessiond",glocal.mysecret,true); setgrouparg ("RSA key server"); setarg (' ',"keysdport","Port to reach the bo-keysd server",glocal.keysdport,false); setgrouparg ("Publish server"); setarg (' ',"publishdport","Port to reach the publishd server",glocal.publishdport,false); setgrouparg ("Misc."); setarg (' ',"secrets","File holding secrets for communication",glocal.secretfile,false); setarg (' ',"user","Run the program as this user",glocal.user,false); setarg (' ',"logfile","Log file to record request",glocal.logfile,false); setarg (' ',"daemon","Run in background",glocal.daemon,false); setarg (' ',"pidfile","File holding the PID of the process",glocal.pidfile,false); setarg (' ',"noproc","Identity of this process (UUID)",glocal.noproc,false); setarg (' ',"bob_dir","Binary file directory",glocal.bob_dir,false); setarg (' ',"private_site","Local users may interact without doing contact request",glocal.private_site,false); setarg (' ',"nodename",MSG_R(O_NODENAME),nodename,true); setarg (' ',"timezones",MSG_U(O_TIMEZONES,"File holding valid time zone names"),glocal.ftimezones,false); setgrouparg ("Mail"); setarg (' ',"mailserver","Mail relay to use",glocal.mailserver,false); setarg (' ',"mailport","TCP port of the relay (or unix socket)",glocal.mailport,false); setarg (' ',"forceaddr","Force email address",glocal.force_addr,false); setarg ( ' ',"mailfrom","Mail sender",glocal.mailfrom,true); setgrouparg ("Database"); setarg (' ',"data_dbserv","Database server",glocal.data_dbserv,false); setarg (' ',"data_dbname","Database name",glocal.data_dbname,false); setarg (' ',"data_dbuser","Database user",glocal.data_dbuser,true); setarg (' ',"users_dbserv","Database server for users",glocal.users_dbserv,false); setarg (' ',"users_dbname","Database name for users",glocal.users_dbname,false); setarg (' ',"users_dbuser","Database user for users",glocal.users_dbuser,true); setarg (' ',"sqltcpport","Database TCP port",glocal.sql_tcpport,false); glocal const char *msg = msg; ("/tmp/err.log",true); fprintf (fout,"%s\n",glocal.msg); return 0; 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); } glocal set timezones; glocal unsigned long nbrequest_client = 0; glocal NSQL *usq; // SQL handle for the users database glocal CONNECT_INFO con; // Connection to the session manager glocal CONTEXT ctx; glocal map secrets; (glocal.ftimezones,true); glocal.timezones.insert(line); return 0; const char *passwd = getenv("BO_WRITED_PWD"); glocal.ctx.mailserver = glocal.mailserver; glocal.ctx.mailfrom = glocal.mailfrom; glocal.ctx.mailport = glocal.mailport; fs_set_noproc (glocal.noproc); if (passwd == NULL){ tlmp_error ("Can't get database password from environment, aborting\n"); exit (-1); } if (glocal.force_addr != NULL) fdpass_set_force_addr(glocal.force_addr); if (glocal.sql_tcpport != NULL) nsql_settcpport (atoi(glocal.sql_tcpport)); query_setdefaultdb (glocal.data_dbserv,glocal.data_dbname,glocal.data_dbuser,passwd); query_getdefaultdb()->showerrormode(true); NSQL nsql_sq (glocal.users_dbserv,glocal.users_dbname,glocal.users_dbuser,passwd); nsql_sq.showerrormode (true); nsql_sq.setunixpath ("/var/lib/mysql/mysql-users.sock"); glocal.usq = &nsql_sq; glocal.ctx.usq = &nsql_sq; fdpass_readsecrets (glocal.secretfile,glocal.secrets); glocal.con.port = glocal.sessionport; glocal.con.bind = glocal.sessionbind; glocal.con.secret = glocal.mysecret; glocal string clientport = string_f ("unix:/tmp/writed-%s.sock",glocal.port); glocal string controlport = string_f ("unix:%s",glocal.control); glocal.ctx.con_keys.port = glocal.keysdport; glocal.ctx.con_publish.port = glocal.publishdport; glocal.ctx.con_publish.secret = glocal.mysecret; glocal.con.fd = -1; int ret = -1; (glocal.bind,glocal.clientport,5); HANDLE_INFO *n = new HANDLE_INFO; info.data = n; if (string_cmp(info.port,glocal.controlport)==0){ n->type = TYPE_CONTROL; }else{ settcpnodelay(true); n->type = TYPE_CLIENT; char addr[20]; const char *addrstr = addr; if (strncmp(info.port,"unix:",5)==0){ addrstr = info.port; }else{ ipnum_ip2a (from,addr); } n->host = addrstr; n->req.secret = fdpass_findsecret (glocal.secrets,addrstr); debug_printf (D_PROTO,"newclient addr=%s secret=%s\n",addrstr,n->req.secret.c_str()); if (n->req.secret.empty()){ endclient = true; tlmp_error ("No secret for client %s\n",addrstr); } } HANDLE_INFO *c = (HANDLE_INFO*)info.data; debug_printf (D_PROTO,"receive line: %s\n",line); if (c->type == TYPE_CONTROL){ (this,c->req,line, info.linelen,endserver, endclient, no,c,c->host.c_str()); vector tb; tb.push_back(string_f("version %s",VERSION)); tb.push_back(string_f("nbrequest %lu",glocal.nbrequest_client)); tb.push_back(string_f("mailctrl %d \"%s\"",glocal.ctx.mailon,fdpass_get_force_addr())); tb.push_back(string_f("filehandle %u",fs_getnbhandle())); tb.push_back(string_f("nodename: %s",nodename)); tb.push_back(string_f("private_site: %s",glocal.private_site ? "yes" : "no")); instrument_status(tb); rep_status (tb); toggle_instrument_file(on); endserver = true; if (on){ debug_seton(); }else{ debug_setoff(); } debug_setfdebug (filename); glocal bool on = on; glocal const char *email = email; (*glocal.usq,"select userid,admin from users where email='%s'",email); if (strcmp(row[1],"0")==0){ if (!glocal.on){ glocal.bo_writed_control.rep_makeadmin(false,"already not admin"); }else if (sql_action(*glocal.usq,"update users set admin=1 where userid=%s",row[0])==-1){ glocal.bo_writed_control.rep_makeadmin(false,"sql error"); }else{ glocal.bo_writed_control.rep_makeadmin(true,""); bo_log_makeadmin (glocal.ctx.flog,glocal.email,glocal.on); } }else if (glocal.on){ glocal.bo_writed_control.rep_makeadmin(false,"already admin"); }else{ if (sql_action(*glocal.usq,"update users set admin=0 where userid=%s",row[0])==-1){ glocal.bo_writed_control.rep_makeadmin(false,"sql error"); }else{ glocal.bo_writed_control.rep_makeadmin(true,""); bo_log_makeadmin (glocal.ctx.flog,glocal.email,glocal.on); } } glocal.bo_writed_control.rep_makeadmin(false,"user unknown"); bool success = false; fclose (glocal.ctx.flog); glocal.ctx.flog = fopen (glocal.logfile,"a"); if (glocal.ctx.flog == NULL){ glocal.TCPSERVER.sendf ("Can't open logfile %s (%s)\n",glocal.logfile,strerror(errno)); tlmp_error ("Can't open logfile %s (%s)\n",glocal.logfile,strerror(errno)); exit (-1); }else{ success = true; } rep_rotatelog (success); bool success = false; fclose (glocal.ctx.flog); glocal.ctx.flog = fopen (glocal.logfile,"w"); if (glocal.ctx.flog == NULL){ glocal.TCPSERVER.sendf ("Can't open logfile %s (%s)\n",glocal.logfile,strerror(errno)); tlmp_error ("Can't open logfile %s (%s)\n",glocal.logfile,strerror(errno)); exit (-1); }else{ success = true; } rep_truncatelog (success); glocal vector emails; time_t ti = time(NULL)-nbseconds; struct tm *tt = localtime(&ti); char date[100]; snprintf (date,sizeof(date)-1,"%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); (*glocal.usq,"select userid,userid_str,email from users where confirmed is null and created <= '%s'",date); if (sql_action(*glocal.usq,"delete from users where userid=%s",row[0])!=-1){ bo_log_del_incomplete(glocal.ctx.flog,row[1]); glocal.emails.push_back(row[2]); sql_action("delete from id2name where userid=%s",row[0]); } rep_del_incomplete(glocal.emails); // Test sending mail int success = fdpass_sendmail (glocal.mailserver,glocal.mailport,glocal.mailfrom,addr,subject,body); rep_sendmail (success); glocal bool to_stdout = to_stdout; glocal bool success = false; glocal string msg; (*glocal.usq,"select name,email,userid_str from users where email='%s' and confirmed is null",email); if (glocal.to_stdout){ glocal.msg = writed_format_mail_newacct(row[0],row[2]); glocal.success = true; }else if (writed_mail_newaccount (glocal.mailserver,glocal.mailport,glocal.mailfrom,row[0],row[1],row[2]) != -1){ glocal.success = true; } rep_newacctresend (glocal.success,glocal.msg); glocal.ctx.mailon = on; if (strcmp(forceaddr,"keep")!=0) fdpass_set_force_addr (forceaddr); string msg; string id_str; translat_selectlang (lang); bo_writed_adduser (glocal.ctx,lang,name,email,password,id_str,msg); if (msg.size() > 0){ rep_adduser (false,msg); }else{ rep_adduser (true,""); } glocal string msg; glocal const char *name = name; (*glocal.usq,"select userid,confirmed,disabled from users where name='%s'" ,name); if (row[1] != NULL){ glocal.msg = "Account already confirmed"; }else if (row[2] != NULL){ glocal.msg = "Account disabled"; }else{ unsigned userid = atoi(row[0]); if (bo_writed_confirmuser (glocal.ctx,userid,glocal.name,"",glocal.msg)==-1){ glocal.msg = "Can't confirm"; } } glocal.msg = "No user with that name"; if (glocal.msg.size() > 0){ rep_confirmuser (false,glocal.msg); }else{ rep_confirmuser (true,""); } // name = success:b msg glocal string msg; (*glocal.usq,"select userid,disabled from users where name='%s' or email='%s'",name,name); glocal.msg = "Unknown account"; if (row[1] != NULL){ glocal.msg = "Account already disabled"; }else if (sql_action (*glocal.usq,"update users set disabled=now() where userid=%s",row[0])==-1){ glocal.msg = "Internal error, table users"; } if (glocal.msg.size() > 0){ rep_disableuser(false,glocal.msg); }else{ rep_disableuser(true,""); } // name = success:b msg glocal string msg; (*glocal.usq,"select userid,disabled,nbfail from users where name='%s' or email='%s'",name,name); glocal.msg = "Unknown account"; unsigned nbfail = atoi(row[2]); if (row[1] == NULL && nbfail==0){ glocal.msg = "Account already enabled"; }else if (sql_action (*glocal.usq,"update users set nbfail=0,disabled=null where userid=%s",row[0])==-1){ glocal.msg = "Internal error, table users"; } if (glocal.msg.size() > 0){ rep_enableuser(false,glocal.msg); }else{ rep_enableuser(true,""); } // name = success:b msg session glocal bool success = false; glocal string msg; glocal string session; // This is a request from admin, so we create a session even if this account is disabled, not confirmed... (*glocal.usq,"select userid,userid_str,name,email,admin from users where name='%s' or email='%s'",name,name); glocal string newsession = fs_makeid (); glocal const char *email = row[3]; glocal string lang = "eng"; glocal unsigned dateformat=0; glocal string timezone; debug_printf (D_PROTO,"login ok\n"); int userid = atoi(row[0]); ("select lang,dateformat,timezone from config where userid=%d",userid); glocal.lang = row[0]; glocal.dateformat = atoi(row[1]); glocal.timezone = row[2]; (glocal.con,glocal.newsession); if (internal_error){ glocal.msg = "Createsession, internal error"; }else{ debug_printf (D_PROTO,"create session ok %s\n",glocal.newsession.c_str()); } if (glocal.msg.empty()){ (glocal.con,glocal.newsession,userid,row[1],row[2],row[3] ,glocal.lang,atoi(row[4]),glocal.dateformat,glocal.timezone); if (internal_error){ glocal.msg = "Internal error"; }else{ debug_printf (D_PROTO,"login session ok %s\n",glocal.newsession.c_str()); sql_action (*glocal.usq,"update users set nbfail=0,lastaccess=now() where email='%s'",glocal.email); glocal.session = glocal.newsession; } } glocal.msg = "Unknown account"; if (glocal.msg.size() > 0){ rep_login (false,glocal.msg,""); }else{ rep_login (true,"",glocal.session); } string msg; if (sql_action(*glocal.usq,"update users set password=password('%s') where name='%s'",password,name)==-1){ msg = "Can't set password"; } if (msg.size() > 0){ rep_setpassword(false,msg); }else{ rep_setpassword(true,""); } // user doit:b keeppublic:u keepother:u keeprss:u min_msgs:u min_pub_msgs:u = success:b msg deleted:u glocal string msg; glocal vector stats; glocal bool doit = doit; glocal const char *user = user; glocal unsigned min_msgs = min_msgs; glocal unsigned min_pub_msgs = min_pub_msgs; glocal unsigned keepother = keepother; glocal unsigned keeprss = keeprss; glocal unsigned keeppublic = keeppublic; ("select userid from id2name where name='%s'",user); glocal.msg = "Unknown user"; ENTRY entry; if (fs_findentry(string_f("/msgs/%s/short-inbox",glocal.user),entry,true,"") != -1){ ("select itemid,name from dirs_content where dirid=%u",entry.entryid); unsigned dirid = atoi(row[0]); const char *name = row[1]; glocal vector items; ("select itemid,modified,eventtime from dirs_content" " where dirid=%u order by eventtime",dirid); glocal.items.emplace_back(atoi(row[0]),row[1],row[2]); unsigned minmsgs = glocal.min_msgs; unsigned keepdays = glocal.keepother; if (strcmp(name,"public")==0){ minmsgs = glocal.min_pub_msgs; if (is_start_any_of(glocal.user,NONEED,"rss:")){ keepdays = glocal.keeprss; }else{ keepdays = glocal.keeppublic; } } time_t date = time(NULL) - keepdays*24*60*60; DATEASC buf; fdpass_asctime(date,buf); buf.buf[4] = '-'; buf.buf[7] = '-'; buf.buf[10] = ' '; DELSTATS stat; stat.group = name; stat.deleted = 0; string eventtime_mark; if (glocal.items.size() > minmsgs){ for (auto const &f:glocal.items){ // tlmp_error ("compare name=%s %s <= %s\n",name,f.eventtime.c_str(),buf.buf); if (f.eventtime <= buf.buf){ eventtime_mark = f.eventtime; stat.deleted++; if (glocal.items.size() - stat.deleted <= minmsgs) break; }else{ break; } } } if (eventtime_mark.size() > 0 && glocal.doit){ // We delete everything in dirid with eventtime <= eventtime_mark if (sql_action("delete from dirs_content where dirid=%u and eventtime <= '%s'" ,dirid,eventtime_mark.c_str())==-1){ tlmp_error ("deleteoldmsgs: Error deleting on dirs_content table, account %s\n" ,glocal.user); } } glocal.stats.push_back(move(stat)); } if (glocal.msg.size() > 0){ rep_deleteoldmsgs (false,glocal.msg,glocal.stats); }else{ rep_deleteoldmsgs (true,"",glocal.stats); } tlmp_error ("Control: Invalid command: %s\n",line); glocal.TCPSERVER.sendf ("Invalid command %s\n",line); endclient = true; }else if (c->type == TYPE_CLIENT){ glocal.nbrequest_client++; (this,c->req,line, info.linelen,endserver, endclient, no,c,c->host.c_str()); string msg; string id_str; translat_selectlang (lang); bo_writed_adduser (glocal.ctx,lang,name,email,password,id_str,msg); rep_adduser (id_str,msg); string msg; if (sql_action(*glocal.usq,"insert into users (name,pub_key,confirmed) values ('%s','%s',now())",user,pubkey)==-1){ msg = "Internal error, users table"; }else{ int userid = glocal.ctx.usq->getlastid(); if (sql_action("insert into id2name (userid,name,pub_key) values (%d,'%s','%s')",userid,user,pubkey)==-1){ msg = "Internal error, id2name table"; }else{ bo_writed_create_group_list(userid,"public","Public view"); bo_writed_create_group (userid,"contacts",false,"",msg); int groupid = bo_writed_create_group (userid,"public",true,"Public view",msg); if (groupid != -1){ bo_writed_set_group(userid,"public","public","R",msg); if (sql_action("insert into group_members (groupid,userid,access,role) values (%u,%u,'W','')" ,groupid,userid)==-1){ tlmp_error ("Internal error setting user %s member of his group public",user); } } sql_action("insert into config (userid,public_view) values (%d,1)",userid); } } if (msg.size() > 0){ rep_addremoteuser (false,msg); }else{ rep_addremoteuser (true,""); } // nodename = success:b msg session 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,glocal.sessionid.c_str()); if (internal_error){ glocal.msg = "Internal error"; }else{ // We preserve the nodename. userid==-2 means not logged yet. (glocal.con,glocal.sessionid ,-2,glocal.nodename,"","","",false,0,"system"); 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; if (bod_sessionstate(glocal.con,session,-2,glocal.nodename,glocal.msg) != -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 -1, it means login completed (glocal.con,glocal.session ,-1,glocal.nodename,"","","",false,0,"system"); 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,session); rep_nodepass(false,glocal.msg); }else{ rep_nodepass(true,""); } // sessionid user sign = success:b msg glocal string msg; glocal const char *user = user; glocal const char *sign = sign; glocal const char *sessionid = sessionid; (*glocal.usq,"select userid,pub_key from users where name='%s'",user); glocal.msg = MSG_R(E_IVLDUSER); unsigned userid = atoi(row[0]); if (row[1] == NULL){ glocal.msg = MSG_R(E_NOPUBKEY); }else{ EVP_PKEY *p = fs_load_public (row[1]); if (p != NULL){ string sig = glocal.sign; strip_end (sig); if (fs_verify(glocal.sessionid,p,sig)==-1){ glocal.msg = MSG_R(E_SIGNOMATCH); }else{ (glocal.con,glocal.sessionid,userid,"",glocal.user,"" ,"eng",false,0,"system"); if (internal_error){ glocal.msg = "Internal error"; }else{ sql_action (*glocal.usq,"update users set lastaccess=now() where name='%s'",glocal.user); } } fs_free_public (p); } } if (glocal.msg.size() > 0){ rep_remotelogin(false,glocal.msg); }else{ rep_remotelogin (true,""); } // sessionid user = success:b msg glocal string msg; glocal string nodename; if (bod_sessionstate(glocal.con,sessionid,-1,glocal.nodename,glocal.msg) != -1){ glocal int userid = fs_rec_getid("select userid from id2name where name='%s'",user); if (glocal.userid == -1){ glocal.msg = "Invalid user"; }else{ ("select 1 from interests_remote where userid=%d and nodename='%s'" ,glocal.userid,glocal.nodename.c_str()); if (sql_action("insert into interests_remote (userid,nodename) values (%d,'%s')" ,glocal.userid,glocal.nodename.c_str())==-1){ glocal.msg = "Internal error, table interests_remote"; } // Already there, ok. } } if (glocal.msg.size() > 0){ rep_remote_interest_set(false,glocal.msg); }else{ rep_remote_interest_set(true,""); } // sessionid user = success:b msg glocal string msg; glocal string nodename; if (bod_sessionstate(glocal.con,sessionid,-1,glocal.nodename,glocal.msg) != -1){ glocal int userid = fs_rec_getid("select userid from id2name where name='%s'",user); if (glocal.userid == -1){ glocal.msg = "Invalid user"; }else{ if (sql_action("delete from interests_remote where userid=%d and nodename='%s'" ,glocal.userid,glocal.nodename.c_str()) == -1){ glocal.msg = "Internal error, table interests_remote"; } } } if (glocal.msg.size() > 0){ rep_remote_interest_set(false,glocal.msg); }else{ rep_remote_interest_set(true,""); } glocal string msg; glocal string email; glocal string name; glocal const char *confirmid = confirmid; translat_selectlang(lang); (*glocal.usq,"select userid,name,email,confirmed from users where userid_str='%s' and disabled is null" ,confirmid); unsigned userid = atoi(row[0]); glocal.name = row[1]; glocal.email = row[2]; // Check if already confirmed if (row[3] != nullptr){ glocal.msg = MSG_U(E_ALREADYCONFIRMED,"Account is already confirmed");; }else if (bo_writed_confirmuser (glocal.ctx,userid,glocal.name,glocal.confirmid,glocal.msg)==-1){ glocal.msg = MSG_U(E_CANTCONFIRM,"Error, can't confirm new user"); } tlmp_error ("Confirm unknown users: confirmid=%s\n",glocal.confirmid); glocal.msg = MSG_U(E_IVLDCONFIRMID,"Error, unknown confirmation ID, maybe the link in the email was truncated ?"); if (glocal.msg.size() > 0){ rep_confirmuser (false,glocal.msg,"",""); }else{ rep_confirmuser (true,"",glocal.email,glocal.name); } // User is deleting his own account glocal const char *sessionid=sessionid; glocal string userid_str; glocal unsigned userid = trli_getsessionuser(glocal.con,sessionid,glocal.userid_str); if (glocal.userid != 0){ glocal string deleteid = fs_makeid(); if (sql_action(*glocal.usq,"update users set deleteid='%s' where userid=%u",glocal.deleteid.c_str() ,glocal.userid)!=-1){ (*glocal.usq,"select email from users where userid=%u",glocal.userid); glocal.bo_writed_client.rep_deleteuser (row[0],glocal.deleteid.c_str()); bo_log_deleteuser (glocal.ctx.flog,glocal.userid_str,glocal.deleteid); } } glocal const char *confirmid = confirmid; (*glocal.usq,"select userid,userid_str from users where deleteid='%s' and deleted is null and disabled is null" ,confirmid); unsigned userid = atoi(row[0]); const char *userid_str = row[1]; if (sql_action(*glocal.usq,"update users set deleted=now() where userid=%u",userid)!=-1){ // And we terminated all sessions for this user (glocal.con,userid); bo_log_confirmdelete (glocal.ctx.flog,userid_str,glocal.confirmid); glocal.bo_writed_client.rep_confirmdelete (true,""); } glocal.bo_writed_client.rep_confirmdelete (false,"no user"); glocal const char *email = email; glocal const char *sessionid = sessionid; (*glocal.usq,"select userid,userid_str,name,email,admin,confirmed from users where email='%s' and password=password('%s')" " and disabled is null and deleted is null and nbfail < 3",email,password); if (row[5] == NULL){ // This account is not confirmed, but the password is good. // So we return an error, but with the clue that it is not confirmed. // The user will be offered to resend the confirmation email glocal.bo_writed_client.rep_login (false,true); if (glocal.ctx.mailon){ writed_mail_newaccount(glocal.ctx.mailserver,glocal.ctx.mailport,glocal.ctx.mailfrom ,row[2],glocal.email,row[1]); } }else{ glocal string lang = "eng"; glocal unsigned dateformat=0; glocal string timezone; debug_printf (D_PROTO,"login ok\n"); int userid = atoi(row[0]); ("select lang,dateformat,timezone from config where userid=%d",userid); glocal.lang = row[0]; glocal.dateformat = atoi(row[1]); glocal.timezone = row[2]; (glocal.con,glocal.sessionid,userid,row[1],row[2],row[3] ,glocal.lang,atoi(row[4]),glocal.dateformat,glocal.timezone); if (internal_error){ glocal.bo_writed_client.rep_login (false,false); }else{ debug_printf (D_PROTO,"login session ok %s\n",glocal.sessionid); sql_action (*glocal.usq,"update users set lastaccess=now() where email='%s'",glocal.email); glocal.bo_writed_client.rep_login (true,false); } } // It fails, why ? debug_printf (D_PROTO,"login failed\n"); (*glocal.usq,"select userid,email,disabled,deleted,confirmed,nbfail from users where email='%s'" ,glocal.email); if (row[2] != NULL || row[3] != NULL || row[4] == NULL){ // disabled or deleted or not confirmed, nothing to do }else if (atoi(row[5]) < 3){ sql_action (*glocal.usq,"update users set nbfail=nbfail+1 where email='%s'",glocal.email); } glocal.bo_writed_client.rep_login (false,false); glocal const char *sessionid=sessionid; string tmp; bool is_admin,is_node; glocal unsigned userid = trli_getsessionuser(glocal.con,sessionid,tmp,is_admin,is_node); if (glocal.userid != 0 || is_node){ (glocal.con,glocal.sessionid); } // Create a web session, not associated with any user glocal string sessionid = fs_makeid (); (glocal.con,glocal.sessionid); if (internal_error){ glocal.bo_writed_client.rep_createsession (""); }else{ debug_printf (D_PROTO,"create session ok %s\n",glocal.sessionid.c_str()); glocal.bo_writed_client.rep_createsession (glocal.sessionid.c_str()); } glocal ENTRY entry; if (bo_writed_findentry (glocal.con,sessionid,name,glocal.entry,false)!=-1){ if (!glocal.entry.may_add){ glocal.entry.msg = MSG_U(E_NOTALLOWED,"Not allowed"); }else if (bo_writed_fname_check(name,glocal.entry.msg)){ glocal int listid = -1; glocal char listmode = 'p'; if (glocal.entry.dirid == 0){ // root dir glocal.listid = 0; }else{ ("select group_list_id,listmode from ids where id=%u",glocal.entry.dirid); glocal.entry.msg = MSG_U(E_NOGROUPLISTID,"Internal error (no group_list_id)"); glocal.listid = atoi(row[0]); glocal.listmode = row[1][0]; } if (glocal.listid != -1){ int subdirid = fs_newid (glocal.entry.userid,glocal.listid,glocal.listmode,glocal.entry.msg); if (subdirid != -1){ if (fs_insert_dir (glocal.entry.dirid,subdirid,glocal.entry.basename)==-1){ glocal.entry.msg = MSG_U(E_DIR_SUBDIRS,"Internal error (dirs_subdirs table)"); } } } } } if (glocal.entry.msg.size() > 0){ rep_mkdir (false,glocal.entry.msg); }else{ rep_mkdir (true,""); } ENTRY entry; if (bo_writed_findentry (glocal.con,sessionid,name,entry,true)==-1){ rep_rmdir (false,entry.msg); }else{ if (!bolixo_isdir(entry.type)){ rep_rmdir (false,"Not a directory, can't delete"); }else{ if (fs_insert_deleted(entry.dirid,entry.entryid,entry.basename,entry.modified)==-1){ rep_rmdir (false,"Internal error (dirs_files table)"); }else{ rep_rmdir (true,"Ok"); } } } ENTRY entry; if (bo_writed_findentry (glocal.con,sessionid,name,entry,false)!=-1 && bo_writed_fname_check(name,entry.msg)){ int fileid = fs_newid (entry.userid,entry.msg); if (fileid != -1){ DATEASC now; fs_set_now(now); string sign = bo_writed_sign (glocal.ctx.con_keys,entry.userid,content); if (fs_insert_file(entry.dirid,fileid,now.buf,entry.basename)==-1){ entry.msg = "Internal error (dirs_files table)"; }else if (sql_action("insert into files (id,modified,filetype,content,signature) values (%d,'%s',%u,'%s','%s')" ,fileid,now.buf,FILE_TEXT,content,sign.c_str())==-1){ entry.msg = "Internal error (files table)"; }else{ bo_writed_update_dirdate(entry.dirid); } } } rep_addfile (entry.msg.size() == 0 ? false : true,entry.msg); ENTRY entry; if (bo_writed_findentry (glocal.con,sessionid,name,entry,false)==-1){ rep_addfile_bob (false,"",entry.msg); }else{ string msg,sign; ADDFILE_INFO info; bo_writed_addfile_bob (glocal.ctx.con_keys,sessionid,entry.basename,ENTRY_FILE,entry.dirid,entry.userid ,content,more,sign ,info,msg); if (msg.size() > 0){ rep_addfile_bob (false,"",msg); fs_delete_handle(info.handle); }else{ if (!more){ fs_delete_handle(info.handle); info.handle.clear(); } rep_addfile_bob (true,info.handle,"Ok"); } } if (trli_getsessionuser(glocal.con,sessionid)==0){ rep_appendfile (false,"Invalid session"); }else{ FILE *fout = fs_get_file (handle,sessionid); if (fout == NULL){ tlmp_error ("Can't open file (%s)\n",strerror(errno)); rep_appendfile (false,"Internal error (3-writing data)"); }else{ size_t size = content.getsize(); if (fwrite (content.getbuffer(),1,size,fout)!=size){ rep_appendfile (false,"Internal error (4-writing data)"); }else{ rep_appendfile (true,"Ok"); } if (!more){ int ownerid,dirid,fileid; string modified,name; if (fs_file_handle_getextra(handle,ownerid,dirid,fileid,modified,name)!=-1 && ownerid != -1){ (glocal.ctx.con_publish,ownerid ,dirid,fileid,modified,name); if (!success) tlmp_error ("publishd_client_sendmessage: %s\n",msg); } fs_delete_handle(handle); } } } ENTRY entry; if (bo_writed_findentry (glocal.con,sessionid,name,entry,true)==-1){ rep_delfile (false,entry.msg); }else{ if (!bolixo_isfile(entry.type)){ rep_delfile (false,MSG_U(E_NOTAFILECANTDEL,"Not a file, can't delete")); }else{ if (fs_insert_deleted(entry.dirid,entry.entryid,entry.basename,entry.modified)==-1){ rep_delfile (false,"Internal error (dirs_files table)"); }else{ rep_delfile (true,"Ok"); bo_writed_update_dirdate(entry.dirid); } } } glocal ENTRY entry; if (bo_writed_findentry (glocal.con,sessionid,dirname,glocal.entry,true)!=-1){ if (!bolixo_isdir(glocal.entry.type)){ glocal.entry.msg = MSG_U(E_NOTDIRUNDEL,"Not a directory, can't undelete"); }else{ // Find the most recent deleted entry ("select itemid,eventtime from dirs_content where dirid=%u and type=%d order by eventtime desc limit 1" ,glocal.entry.entryid,ENTRY_DELETED); glocal.entry.msg = MSG_U(E_NODELETED,"no deleted entries in this folder"); if (sql_action("delete from dirs_content where dirid=%u and itemid=%s and eventtime='%s'" ,glocal.entry.entryid,row[0],row[1])==-1){ glocal.entry.msg = "Internal error (dirs_content table)"; } } } if (glocal.entry.msg.size() > 0){ rep_undelete (false,glocal.entry.msg); }else{ rep_undelete(true,""); } ENTRY entry; if (bo_writed_findentry (glocal.con,sessionid,name,entry,true)==-1){ rep_modifyfile (false,entry.msg); }else if (!entry.may_add){ rep_modifyfile_bob (false,"",MSG_R(E_NOTALLOWED)); }else{ // tlmp_error ("userid=%d name=%s may_add=%d\n",entry.userid,name,entry.may_add); if (!bolixo_isfile(entry.type)){ rep_modifyfile (false,"Not a file, can't modify"); }else{ DATEASC now; fs_set_now(now); string sign = bo_writed_sign (glocal.ctx.con_keys,entry.userid,content); unsigned modifiedby = entry.userid != entry.ownerid ? entry.userid : 0; if (fs_insert_file (entry.dirid,entry.entryid,now.buf,entry.basename)==-1){ rep_modifyfile (false,"Internal error (dirs_files table)"); }else if (sql_action("insert into files (id,modified,filetype,content,signature,modifiedby) values (%d,'%s',%u,'%s','%s',%u)" ,entry.entryid,now.buf,FILE_TEXT,content,sign.c_str(),modifiedby)==-1){ rep_modifyfile (false,"Internal error (files table)"); }else{ rep_modifyfile (true,"Ok"); } } } ENTRY entry; if (bo_writed_findentry (glocal.con,sessionid,name,entry,true)!=-1){ if (sql_action("insert into marks (userid,itemid,modified) values (%u,%u,'%s') on duplicate key update modified='%s'" ,entry.userid,entry.entryid,entry.modified.c_str(),entry.modified.c_str())==-1){ entry.msg = "internal error (table marks)"; }else{ entry.msg = ""; } } if (entry.msg.size() == 0){ rep_markview (true,""); }else{ rep_markview (false,entry.msg); } // sessionid name listname listmode = success:b msg glocal ENTRY entry; glocal const char *listmode = listmode; if (bo_writed_findentry (glocal.con,sessionid,name,glocal.entry,true)!=-1){ if (glocal.entry.userid != glocal.entry.ownerid && !glocal.entry.is_admin){ glocal.entry.msg = "Only owner may assign access"; }else if (username[0] != '\0' && !glocal.entry.is_admin){ glocal.entry.msg = "Only admin may assign ownership of a file/directory"; }else{ if (strcmp(listname,"-")==0){ if (sql_action("update ids set group_list_id=NULL,listmode='%s' where id=%u",listmode,glocal.entry.entryid)==-1){ glocal.entry.msg = "Internal error (ids table)"; }else{ glocal.entry.msg = ""; } }else if (strcmp(listname,ALL_MAY_READ)==0){ if (sql_action("update ids set group_list_id=0,listmode='%s' where id=%u",listmode,glocal.entry.entryid)==-1){ glocal.entry.msg = "Internal error (ids table)"; }else{ glocal.entry.msg = ""; } }else if (listname[0] != '\0'){ int group_list_id = fs_rec_getid ("select id from group_lists where ownerid=%u and name='%s'",glocal.entry.userid,listname); if (group_list_id == -1){ glocal.entry.msg = "Invalid list name"; }else if (sql_action("update ids set group_list_id=%d,listmode='%s' where id=%u",group_list_id,glocal.listmode,glocal.entry.entryid)==-1){ glocal.entry.msg = "Internal error (ids table)"; }else{ glocal.entry.msg = ""; } }else{ glocal.entry.msg = string_f("listname must be either a valid list name, - or %s",ALL_MAY_READ); } if (glocal.entry.msg.size() == 0 && username[0] != '\0'){ int username_id = fs_rec_getid ("select userid from id2name where name='%s'",username); if (username_id == -1){ glocal.entry.msg = "Invalid user name"; }else if (sql_action("update ids set ownerid=%d where id=%u",username_id,glocal.entry.entryid)==-1){ glocal.entry.msg = "Internal error (ids table)"; }else{ glocal.entry.msg = ""; } } } } if (glocal.entry.msg.size() > 0){ rep_set_access (false,glocal.entry.msg); }else{ rep_set_access (true,""); } // sessionid name content:o more:b = success:b handle msg ENTRY entry; if (bo_writed_findentry (glocal.con,sessionid,name,entry,true)==-1){ rep_modifyfile_bob (false,"",entry.msg); }else if (!entry.may_add){ rep_modifyfile_bob (false,"",MSG_R(E_NOTALLOWED)); }else{ // tlmp_error ("userid=%d ownerid=%d name=%s may_add=%d\n",entry.userid,entry.ownerid,name,entry.may_add); string msg; string handle; if (!bolixo_isfile(entry.type)){ msg = "Not a file, can't modify"; }else{ DATEASC now; fs_set_now(now); FILE_TYPE file_type = bo_writed_file_type (entry.basename,content,more); const char *ptsign = NULL; string sign; if (!more){ sign = bo_writed_sign (glocal.ctx.con_keys,entry.userid,content); ptsign = sign.c_str(); } unsigned modifiedby = entry.userid != entry.ownerid ? entry.userid : 0; if (fs_insert_file (entry.dirid,entry.entryid,now.buf,entry.basename)==-1){ msg = "Internal error (dirs_files table)"; }else if (sql_action("insert into files (id,modified,filetype,content,signature,modifiedby) values (%d,'%s',%u,NULL,'%s',%u)" ,entry.entryid,now.buf,file_type,ptsign,modifiedby)==-1){ msg = "Internal error (files table)"; }else{ FILE *fout = fs_alloc_file_handle (entry.entryid,now.buf,"w",handle,sessionid); if (fout == NULL){ tlmp_error ("Can't open file (%s)\n",strerror(errno)); msg = "Internal error (1-writing data)"; }else{ size_t size = content.getsize(); if (fwrite (content.getbuffer(),1,size,fout)!=size){ msg = "Internal error (2-writing data)"; } } } } if (msg.size() > 0){ rep_modifyfile_bob (false,"",msg); fs_delete_handle(handle); }else{ if (!more){ fs_delete_handle(handle); handle.clear(); } rep_modifyfile_bob (true,handle,"Ok"); } } // sessionid oldname newname // oldname is a path, newname is just a name inside the same directory ENTRY oldentry,newentry; if (bo_writed_findentry (glocal.con,sessionid,oldname,oldentry,true)==-1){ rep_rename (false,oldentry.msg); }else if (bo_writed_findentry (glocal.con,sessionid,newname,newentry,false)==-1){ rep_rename (false,newentry.msg); }else{ DATEASC now; fs_set_now(now); // We insert a deletion of the oldname, followed by a creation of the newname with the same // modified date (pointing to the same data) if (sql_action("insert into dirs_content (dirid,itemid,modified,type,name) values (%d,%d,'%s',%u,'%s'), (%d,%d,'%s',%u,'%s')" ,oldentry.dirid,oldentry.entryid,now.buf,ENTRY_DELETED,oldentry.basename.c_str() ,newentry.dirid,oldentry.entryid,oldentry.modified.c_str(),oldentry.type,newentry.basename.c_str())==-1){ rep_rename (false,"Internal error (dirs_content table)"); }else{ rep_rename (true,"Ok"); bo_writed_update_dirdate(oldentry.dirid); if (newentry.dirid != oldentry.dirid) bo_writed_update_dirdate(newentry.dirid); } } // sessionid srcname srcdate dstname // srcname and dstname are path // srcname may point to a message public folder made public by the owner. So normal access right do not apply. // bo_writed_findenry does not handle this situation. Since only copy and sendtalk_file needs that, bo_writed_findentry // won't do it (It is used all over the place). // So we check first the public case here. If this is the case, we force bo_writed_findentry into admin mode. string msg; ENTRY srcentry,dstentry; bool is_msg = strncmp(dstname,"/msgs/",6)==0; bool force_admin = bo_writed_public_msg (srcname); if (bo_writed_findentry (glocal.con,sessionid,srcname,srcdate,srcentry,true,force_admin)==-1){ msg = srcentry.msg; }else if (bo_writed_findentry (glocal.con,sessionid,dstname,dstentry,false)==-1){ msg = dstentry.msg; }else if (bolixo_isdir(srcentry.type)){ if (is_msg){ msg = MSG_U(E_ONLYFILE,"Only files may be copied in a message folder"); }else{ // Error message will be in msg. bo_writed_copydir (srcentry.entryid,dstentry.dirid,dstentry.basename,srcentry.userid,msg); } }else if (!bolixo_isfile(srcentry.type)){ msg = MSG_U(E_ONLYFILEANDDIR,"Copy only works on files and directories for now"); }else{ // We insert a row so the new name still points to the same entryid and same date. // It means that the new file will always be associated with the same entryid. // The solution would be to allocate a new id and copy the data. ENTRY_TYPE type = is_msg ? ENTRY_MSG : ENTRY_FILE; if (fs_insert_entry(dstentry.dirid,srcentry.entryid,srcentry.modified,dstentry.basename,type,srcentry.userid)==-1){ msg = "Internal error (dirs_content table)"; } } if (msg.size() > 0){ rep_copy (false,msg); }else{ rep_copy (true,""); } // sessionid listname owner = success:b msg string msg; string username; unsigned userid = bo_writed_get_group_owner (glocal.con, sessionid, owner, username, msg); if (userid != 0){ bo_writed_create_project_dir (userid,username,listname,msg); } if (msg.size()==0){ rep_create_project_dir(true,""); }else{ rep_create_project_dir(false,msg); } // sessionid listname owner = success:b msg glocal string msg; glocal const char *listname = listname; glocal string username; glocal unsigned userid = bo_writed_get_group_owner (glocal.con, sessionid, owner, glocal.username,glocal.msg); if (glocal.userid != 0){ if (bo_writed_group_check(listname,glocal.msg)){ ("select id from group_lists where ownerid=%u and name='%s'" ,glocal.userid,listname); glocal.msg = string_f(MSG_U(E_PRJEXIST,"Project %s already exist"),glocal.listname); if (bo_writed_create_group_list(glocal.userid,glocal.username,glocal.listname,"",glocal.msg)==-1){ glocal.msg = "Internal error (group_lists table)"; }else{ glocal.msg = ""; } }else{ glocal.msg = MSG_U(E_IVLDPROJECTNAME,"Invalid project name"); } } if (glocal.msg.size()==0){ rep_create_group_list (true,""); }else{ rep_create_group_list (false,glocal.msg); } // sessionid groupname owner = success:b msg glocal string msg; glocal const char *groupname = groupname; glocal unsigned userid = bo_writed_get_group_owner (glocal.con, sessionid, owner, glocal.msg); if (glocal.userid != 0){ if (bo_writed_group_check(groupname,glocal.msg)){ ("select id from groups where ownerid=%u and name='%s'" ,glocal.userid,groupname); glocal.msg = "Group alreay exist"; bo_writed_create_group(glocal.userid,glocal.groupname,true,"",glocal.msg); }else{ glocal.msg = MSG_U(E_IVLDGROUPNAME,"Invalid group name"); } } if (glocal.msg.size()==0){ rep_create_group (true,""); }else{ rep_create_group (false,glocal.msg); } // sessionid listname groupname defaultaccess owner = success:b msg string msg; unsigned userid = bo_writed_get_group_owner (glocal.con, sessionid, owner, msg); if (defaultaccess[0] != '\0' && strcmp(defaultaccess," ")!=0 && strcmp(defaultaccess,"R")!=0 && strcmp(defaultaccess,"W")!=0 && strcmp(defaultaccess,"A")!=0 && strcmp(defaultaccess,"-")!=0){ msg = "Invalid default access (' ','R','W','A','-')"; }else if (userid != 0){ bo_writed_set_group(userid,listname,groupname,defaultaccess,msg); } if (msg.size()==0){ rep_create_group (true,""); }else{ rep_create_group (false,msg); } // sessionid groupname user access role owner = success:b msg glocal string msg; glocal const char *groupname = groupname; glocal const char *user = user; //if (role[0] == '\0') role = NULL; glocal const char *role = role; glocal string access = toupper(access); glocal string username; glocal unsigned userid = bo_writed_get_group_owner (glocal.con, sessionid, owner, glocal.username,glocal.msg); if (is_not_in(glocal.access,""," ","R","W","A","-")){ glocal.msg = MSG_U(E_IVLDDEFACCESS,"Invalid access (' ','R','W','A','-')"); }else if (glocal.userid != 0){ ("select id from groups where ownerid=%u and name='%s'",glocal.userid,glocal.groupname); glocal.msg = "Group does not exist"; glocal unsigned groupid = atoi(row[0]); ("select userid from id2name where name='%s'",glocal.user); glocal.msg = MSG_U(E_UNKNOWNUSER,"User does not exist"); glocal unsigned member_userid = atoi(row[0]); glocal bool allowed = true; // A user is allways allowed to put himself in one of his group // If this is not the case, and not a private site, we have to check // that the user is in the contact list if (glocal.userid != glocal.member_userid && !glocal.private_site){ ("select 1 from contact_requests" " where ((userid=%u and reqid=%u) or (userid=%u and reqid=%u)) and status=%d" ,glocal.userid,glocal.member_userid ,glocal.member_userid,glocal.userid,CONTACT_ACCEPTED); glocal.allowed = false; } if (!glocal.allowed){ glocal.msg = "User not in contact"; }else{ ("select 1 from group_members" " where groupid=%u and userid=%u" ,glocal.groupid,glocal.member_userid); if (glocal.access[0] == '-'){ if (sql_action("delete from group_members" " where groupid=%u and userid=%u" ,glocal.groupid,glocal.member_userid)==-1){ glocal.msg = "Internal error (group_members table)"; }else{ glocal.msg = ""; } }else if (sql_action("update group_members set access='%s',role='%s'" " where groupid=%u and userid=%u" ,glocal.access.c_str(),glocal.role,glocal.groupid,glocal.member_userid)==-1){ glocal.msg = "Internal error (group_members table)"; }else{ glocal.msg = ""; } if (glocal.access[0] == '-'){ glocal.msg = "User was not a member of that group"; }else if (sql_action("insert into group_members (groupid,userid,access,role) values (%u,%u,'%s','%s')" ,glocal.groupid,glocal.member_userid,glocal.access.c_str(),glocal.role)==-1){ glocal.msg = "Internal error (group_members table)"; }else{ glocal.msg = ""; } } } if (glocal.msg.size()==0){ rep_create_group (true,""); }else{ rep_create_group (false,glocal.msg); } // sessionid listname description owner = success:b msg glocal string msg; glocal const char *listname = listname; glocal const char *description = description; glocal unsigned userid = bo_writed_get_group_owner (glocal.con, sessionid, owner, glocal.msg); if (glocal.userid != 0) ("select id from group_lists where ownerid=%u and name='%s'",glocal.userid,listname); if (sql_action("update group_lists set description='%s' where ownerid=%u and name='%s'" ,glocal.description,glocal.userid,glocal.listname)==-1){ glocal.msg = "Internal error (Table group_lists)"; }else{ glocal.msg = ""; } glocal.msg = "No list with that name"; { } if (glocal.msg.size()==0){ rep_set_list_desc (true,""); }else{ rep_set_list_desc (false,glocal.msg); } // sessionid groupname description owner = success:b msg glocal string msg; glocal const char *groupname = groupname; glocal const char *description = description; glocal unsigned userid = bo_writed_get_group_owner (glocal.con, sessionid, owner, glocal.msg); if (glocal.userid != 0) ("select id from groups where ownerid=%u and name='%s'",glocal.userid,groupname); if (sql_action("update groups set description='%s' where ownerid=%u and name='%s'" ,glocal.description,glocal.userid,glocal.groupname)==-1){ glocal.msg = "Internal error (Table groups)"; }else{ glocal.msg = ""; } glocal.msg = "No group with that name"; { } if (glocal.msg.size()==0){ rep_set_group_desc (true,""); }else{ rep_set_group_desc (false,glocal.msg); } // sessionid listname owner = success:b msg glocal string msg; glocal const char *listname = listname; glocal unsigned userid = bo_writed_get_group_owner (glocal.con, sessionid, owner, glocal.msg); if (glocal.userid != 0) ("select 1 from group_lists where ownerid=%u and name='%s'",glocal.userid,listname); if (sql_action("delete from group_lists where ownerid=%u and name='%s'",glocal.userid,glocal.listname)==-1){ glocal.msg = "Internal error (Table group_lists)"; }else{ glocal.msg = ""; } glocal.msg = "No list with that name"; { } if (glocal.msg.size()==0){ rep_delete_list (true,""); }else{ rep_delete_list (false,glocal.msg); } // sessionid groupname owner = success:b msg glocal string msg; glocal const char *groupname = groupname; glocal unsigned userid = bo_writed_get_group_owner (glocal.con, sessionid, owner, glocal.msg); if (glocal.userid != 0) // Find if the group exists ("select id from groups where ownerid=%u and name='%s'",glocal.userid,groupname); glocal unsigned groupid = atoi(row[0]); // Is this group part of any list ("select 1 from group_list_members where groupid=%u limit 1",glocal.groupid); glocal.msg = "This group is a member of at least one list"; if (sql_action("delete from group_members where groupid=%u",glocal.groupid)==-1){ glocal.msg = "Internal error (Table group_members)"; }else if (sql_action("delete from groups where ownerid=%u and name='%s'",glocal.userid,glocal.groupname)==-1){ glocal.msg = "Internal error (Table groups)"; }else{ glocal.msg = ""; } glocal.msg = "No group with that name"; { } if (glocal.msg.size()==0){ rep_delete_list (true,""); }else{ rep_delete_list (false,glocal.msg); } // sessionid owner recipients:v title content = success:b msg msgid string msg; string rep_msgid; bo_writed_sendmsg (glocal.con,glocal.ctx.con_keys,sessionid,owner,recipients,NULL,title,content,msg,rep_msgid); if (msg.size()==0){ rep_sendmsg (true,"",rep_msgid); }else{ rep_sendmsg (false,msg,""); } // sessionid owner manager project role title content = success:b msg msgid string msg; string rep_msgid; if (bo_writed_project_msg(glocal.con,glocal.ctx.con_keys,sessionid,owner,manager,project,role,NULL,title,content,msg,rep_msgid)!=-1){ rep_sendmsg_project (true,"",rep_msgid); }else{ rep_sendmsg_project (false,msg,""); } // sessionid owner msgid recipients:v title content = success:b msg replyid string msg; string rep_msgid; bo_writed_sendmsg (glocal.con,glocal.ctx.con_keys,sessionid,owner,recipients,msgid,title,content,msg,rep_msgid); if (msg.size()==0){ rep_replymsg (true,"",rep_msgid); }else{ rep_replymsg (false,msg,""); } // sessionid owner manager project role msgid title content = success:b msg replyid string msg; string rep_msgid; if (bo_writed_project_msg(glocal.con,glocal.ctx.con_keys,sessionid,owner,manager,project,role,msgid,title,content,msg,rep_msgid)!=-1){ rep_replymsg_project (true,"",rep_msgid); }else{ rep_replymsg_project (false,msg,""); } // sessionid owner msgid content:o more:b = success:b msg handle // sessionid to content:o = success:b msg handle glocal const char *sessionid = sessionid; glocal const char *to = to; glocal string msg; glocal string handle; glocal const BOB_TYPE *content = &content; glocal bool more = more; ("select id2name.userid,id2name.name,anon_messages from id2name join config on config.userid=id2name.userid" " where id2name.name='%s'",to); glocal.msg = MSG_R(E_IVLDUSER); unsigned userid = atoi(row[0]); const char *username = row[1]; unsigned anon_messages = atoi(row[2]); if (!anon_messages){ glocal.msg = MSG_U(E_ANON_MESSAGES,"This user do not accept anonymous messages"); }else{ bool created; int dirid = fs_find_short_inbox (userid,glocal.to,"anonymous",glocal.msg,true,created); if (dirid != -1){ string sign; ADDFILE_INFO info; bo_writed_addfile_bob (glocal.ctx.con_keys,glocal.sessionid,NULL,ENTRY_MSG,dirid,userid ,*glocal.content,glocal.more,sign ,info,glocal.msg); glocal.handle = info.handle; string email_title,email_content; bo_writed_set_email_notify ("",username,"anonymous",info.file_type,*glocal.content,email_title,email_content); string tmp = string_f("talks:%s:anonymous",username); bo_writed_notify(glocal.ctx,glocal.con,tmp,userid,email_title,email_content); } } if (glocal.msg.size() > 0){ rep_sendtalk_anon (false,glocal.msg,""); fs_delete_handle(glocal.handle); }else{ if (!more){ fs_delete_handle(glocal.handle); glocal.handle.clear(); } rep_sendtalk_anon (true,glocal.msg,glocal.handle); } // sessionid owner to:v groupname groupowner content:o more:b filename sign = success:b msg handle glocal const char *sessionid = sessionid; glocal const BOB_TYPE *content = &content; glocal bool more = more; glocal string username; glocal string handle; glocal string msg; glocal const char *groupname = groupname; glocal const char *groupowner = groupowner; glocal const char *filename = filename; glocal string sign = sign; bool is_admin; glocal unsigned userid = bo_writed_get_group_owner (glocal.con, sessionid, owner, glocal.username, glocal.msg, is_admin); if (glocal.userid > 0){ // sendtalk (and sendtalk_file) may send to a group, to a list of users, or both. // so to[] may be empty and the groupnname may be empty. Not both. glocal vector> uids; bo_writed_check_recipients(glocal.userid,to,glocal.uids,glocal.msg,is_admin); if (to.size() == 0 && groupname[0] == '\0'){ glocal.msg = MSG_U(E_NODEST,"No recipient specified (users or group)"); }else if (glocal.msg.size() == 0){ if (groupname[0] != '\0'){ // We store the message in the short inbox of the group owner (like mail sent to the project) // The query is to check if the user posting the message is a member of the group // and to validate the group exist ("select groups.ownerid,groups.id,groups.name,id2name.name from groups" " join id2name on id2name.userid=groups.ownerid" " join group_members on group_members.groupid = groups.id" " where id2name.name='%s' and groups.name='%s' and group_members.userid=%u" ,groupowner,groupname,glocal.userid); glocal.msg = MSG_U(E_UNKNOWNGROUP,"Unknown group name, empty group, or user not a member"); bool created; unsigned ownerid = atoi(row[0]); unsigned group_id = atoi(row[1]); const char *bd_group_name = row[2]; const char *bd_group_owner = row[3]; int dirid = fs_find_short_inbox (ownerid,bd_group_owner,bd_group_name,glocal.msg,true,created); if (dirid != -1){ ADDFILE_INFO info; const char *ptr_name = glocal.filename[0] != '\0' ? glocal.filename : NULL; bo_writed_addfile_bob (glocal.ctx.con_keys,glocal.sessionid,ptr_name,ENTRY_MSG,dirid,glocal.userid ,*glocal.content,glocal.more,glocal.sign ,info,glocal.msg); glocal.handle = info.handle; string email_title,email_content; bo_writed_set_email_notify (glocal.username,glocal.groupowner,glocal.groupname,info.file_type,*glocal.content ,email_title,email_content); bool remote_user = bo_writed_remote_user(glocal.username); if (remote_user){ if (created){ bo_writed_update_interest_table(ownerid,dirid); } }else{ bo_writed_update_interest(created,bd_group_name,ownerid,dirid); if (strcmp(bd_group_name,"public")==0){ if (!glocal.more){ (glocal.ctx.con_publish,ownerid ,dirid,info.fileid,info.modified.buf,info.fileuuid); if (!success) tlmp_error ("publishd_client_sendmessage: %s\n",msg); }else{ fs_file_handle_addextra (glocal.handle,ownerid,dirid,info.fileuuid); } // Add notification for the main page for those who have interests // for this user glocal vector interested; ("select userid from interests where check_userid=%u",ownerid); glocal.interested.push_back(atoi(row[0])); string empty_title,empty_content; // No email notification for the main screen. bo_writed_notify(glocal.ctx,glocal.con,"main",glocal.interested,email_title,empty_content); } } // We send a notification to each members of the group glocal vector members; ("select userid from group_members where groupid=%u",group_id); unsigned userid = atoi(row[0]); // No notification needed to the author of the message if (userid != glocal.userid){ glocal.members.push_back(userid); } { string tmp = string_f("talks:%s:%s",bd_group_owner,bd_group_name); bo_writed_notify (glocal.ctx,glocal.con,tmp,glocal.members,email_title,email_content); } // Now that we have created the message in the group, we // simply link the message in all recipients, except remote user. for (auto &u:glocal.uids){ bool created; if (!bo_writed_remote_user(u.first)){ int udirid = fs_find_short_inbox (u.second,u.first,"inbox",glocal.msg,true,created); if (udirid != -1){ if (fs_insert_entry(udirid,info.fileid,info.modified.buf,info.fileuuid,ENTRY_MSG,ownerid)==-1){ tlmp_error ("Insert in short user inbox, internal error %s\n",u.first.c_str()); break; } bo_writed_set_email_notify (glocal.username,u.first,"inbox",info.file_type,*glocal.content,email_title,email_content); bo_writed_notify_talk_inbox(glocal.ctx,glocal.con,u.first,u.second,email_title,email_content); }else{ tlmp_error ("Insert in short user inbox, missing inbox, internal error %s\n",u.first.c_str()); break; } } } } end = true; }else if (to.size() > 0){ // No group, only recipients. We create the message in the first user inbox // and then link it into the other inboxes. // Now, there is a problem with remote user. The message is copied on their server // We remove the remote users from the uids vector and process with the remaining ones // The bod server, once bo-writed has done the job and validated everything // will dispatch the message to remote users. for (auto p=glocal.uids.begin(); p != glocal.uids.end();){ if (bo_writed_remote_user(p->first)){ p = glocal.uids.erase(p); }else{ p++; } } if (glocal.uids.size() > 0){ bool created; auto &uid0 = glocal.uids[0]; int dirid = fs_find_short_inbox (uid0.second,uid0.first,"inbox",glocal.msg,true,created); if (dirid != -1){ ADDFILE_INFO info; bo_writed_addfile_bob (glocal.ctx.con_keys,glocal.sessionid,NULL,ENTRY_MSG,dirid,glocal.userid ,*glocal.content,glocal.more,glocal.sign ,info,glocal.msg); string email_title,email_content; bo_writed_set_email_notify (glocal.username,uid0.first,"inbox",info.file_type,*glocal.content,email_title,email_content); glocal.handle = info.handle; bo_writed_notify_talk_inbox(glocal.ctx,glocal.con,uid0.first,uid0.second,email_title,email_content); glocal.uids.erase(glocal.uids.begin()); for (auto &u:glocal.uids){ bool created; int udirid = fs_find_short_inbox (u.second,u.first,"inbox",glocal.msg,true,created); if (udirid != -1){ if (fs_insert_entry(udirid,info.fileid,info.modified.buf,info.fileuuid,ENTRY_MSG,glocal.userid)==-1){ tlmp_error ("Insert in short user inbox, internal error %s\n",u.first.c_str()); break; } bo_writed_set_email_notify (glocal.username,u.first,"inbox",info.file_type,*glocal.content ,email_title,email_content); bo_writed_notify_talk_inbox(glocal.ctx,glocal.con,u.first,u.second,email_title,email_content); }else{ tlmp_error ("Insert in short user inbox, missing inbox, internal error %s\n",u.first.c_str()); break; } } } } } } } if (glocal.msg.size() > 0){ rep_sendtalk (false,glocal.msg,"",""); fs_delete_handle(glocal.handle); }else{ if (!more){ fs_delete_handle(glocal.handle); glocal.handle.clear(); } rep_sendtalk (true,glocal.msg,glocal.handle,glocal.sign); } // sessionid owner to:v groupname groupowner filename filedate = success:b msg glocal string msg; glocal const char *groupname = groupname; glocal const char *groupowner = groupowner; glocal ENTRY srcentry; bool force_admin = bo_writed_public_msg (filename); if (bo_writed_findentry (glocal.con,sessionid,filename,filedate,glocal.srcentry,true,force_admin)==-1){ glocal.msg = glocal.srcentry.msg; }else{ // We store the message in the short inbox of the group owner (like mail sent to the project) // The query is to check if the user posting the message is a member of the group // and to validate the group exist ("select groups.ownerid from groups" " join id2name on id2name.userid=groups.ownerid" " join group_members on group_members.groupid = groups.id" " where id2name.name='%s' and groups.name='%s' and group_members.userid=%u" ,groupowner,groupname,glocal.srcentry.userid); glocal.msg = MSG_R(E_UNKNOWNGROUP); bool created; unsigned ownerid = atoi(row[0]); int dirid = fs_find_short_inbox (ownerid,glocal.groupowner,glocal.groupname,glocal.msg,true,created); if (dirid != -1){ string newname = fs_makeid(); if (fs_insert_entry(dirid,glocal.srcentry.entryid,glocal.srcentry.modified ,newname,ENTRY_MSG,glocal.srcentry.userid)==-1){ glocal.msg = "Internal error (dirs_content table)"; }else{ bo_writed_update_dirdate(dirid); } bo_writed_update_interest(created,glocal.groupname,ownerid,dirid); if (strcmp(glocal.groupname,"public")==0){ (glocal.ctx.con_publish,ownerid ,dirid,glocal.srcentry.entryid,glocal.srcentry.modified,newname); if (!success) tlmp_error ("publishd_client_sendmessage: %s\n",msg); } } end = true; } if (glocal.msg.size() > 0){ rep_sendtalk_file (false,glocal.msg); }else{ rep_sendtalk_file (true,glocal.msg); } // sessionid owner user intro = success:b msg // The currently logged user (or owner) is setting a contact request with user // so it is writing in the contact_requests of user glocal string username; glocal string msg; glocal const char *intro = intro; glocal unsigned userid = bo_writed_get_group_owner (glocal.con, sessionid, owner, glocal.username, glocal.msg); if (glocal.userid > 0){ string s_user = bo_writed_remove_localnode(user); user = s_user.c_str(); glocal int target_userid = fs_rec_getid ("select userid from id2name where name='%s'",user); if (glocal.target_userid == -1){ glocal.msg = MSG_U(E_UNKOWNUSER,"Unknown user"); }else{ ("select userid from contact_requests" " where (userid=%u and reqid=%d) or (userid=%d and reqid=%u)" ,glocal.userid,glocal.target_userid,glocal.target_userid,glocal.userid); unsigned userid = atoi(row[0]); if (userid == glocal.userid){ glocal.msg = MSG_U(E_DONEBYCONTACT,"Contact request already performed by your contact"); }else{ glocal.msg = MSG_U(E_CONTACTDONE,"Contact request already performed by you"); } if (sql_action("insert into contact_requests (userid,reqid,message) values (%d,%u,'%s')" ,glocal.target_userid,glocal.userid,glocal.intro)==-1){ glocal.msg = "Can't insert in contact_request"; } string email_title = MSG_U(I_EMAILNOTIFICATION,"Bolixo.org notification"); string email_content = NOTIFY_PROFILE_CONTACTS; bo_writed_notify(glocal.ctx,glocal.con,"profile:Contacts",glocal.target_userid,email_title,email_content); } } if (glocal.msg.size()!=0){ rep_contact_request (false,glocal.msg); }else{ rep_contact_request (true,""); } // sessionid owner user status:e{CONTACT_STATUS} = success:b msg // The currently logged user (or owner) is managing (accept, reject) a contact request from user glocal CONTACT_STATUS status = status; glocal string username; glocal string msg; glocal unsigned userid = bo_writed_get_group_owner (glocal.con, sessionid, owner, glocal.username, glocal.msg); if (glocal.userid > 0){ string s_user = bo_writed_remove_localnode(user); user = s_user.c_str(); glocal const char *target_user = user; glocal int target_userid = fs_rec_getid ("select userid from id2name where name='%s'",user); if (glocal.target_userid == -1){ glocal.msg = MSG_R(E_UNKNOWNUSER); }else{ ("select status from contact_requests where userid=%u and reqid=%d" ,glocal.userid,glocal.target_userid); glocal.msg = "No contact request from this user"; CONTACT_STATUS s = (CONTACT_STATUS)atoi(row[0]); if (s != CONTACT_WAITING){ glocal.msg = MSG_U(E_CONTACTMANAGED,"Contact request for this user already managed"); }else if (sql_action("update contact_requests set status=%d where userid=%u and reqid=%d" ,glocal.status,glocal.userid,glocal.target_userid)==-1){ glocal.msg = "Can't update contact_request"; }else{ bool add = glocal.status == CONTACT_ACCEPTED; // We put or remove users from each other contacts group bo_writed_group_member(glocal.userid,"contacts",glocal.target_userid,"R",add,glocal.msg); bo_writed_group_member(glocal.target_userid,"contacts",glocal.userid,"R",add,glocal.msg); // Send a message to the user about his request string message; if (add){ message = string_f(MSG_U(I_CONTACTREQACCEPTED,"Your contact request sent to %s was accepted") ,glocal.username.c_str()); }else{ message = string_f(MSG_U(I_CONTACTREQREFUSED,"Your contact request sent to %s was rejected") ,glocal.username.c_str()); } if (!bo_writed_remote_user(glocal.target_user)){ bo_writed_send_admin_msg (glocal.ctx.con_keys,glocal.target_userid,glocal.target_user,message); } string email_title = MSG_R(I_EMAILNOTIFICATION); string email_content; // Not done bo_writed_notify(glocal.ctx,glocal.con,NOTIFY_PROFILE_CONTACT_REQ,glocal.target_userid,email_title,email_content); } } } if (glocal.msg.size()!=0){ rep_contact_manage (false,glocal.msg); }else{ rep_contact_manage (true,""); } // sessionid owner key ui:b email:b digest:b = success:b msg glocal string msg; unsigned userid = bo_writed_get_group_owner (glocal.con, sessionid, owner,glocal.msg); if (userid > 0){ if (sql_action("insert into notifications (userid,notify_key,ui,email,digest)" " values (%u,'%s',%u,%u,%u)" " on duplicate key update ui=%u,email=%u,digest=%u" ,userid,key,ui,email,digest ,ui,email,digest)==-1){ glocal.msg = "Internal error writing to table notifications"; } } if (glocal.msg.size() > 0){ rep_set_notification (false,glocal.msg); }else{ rep_set_notification (true,""); } // sessionid owner config:U{CONFIG} = success:b msg glocal string msg; string username; glocal unsigned userid = bo_writed_get_group_owner (glocal.con, sessionid, owner, username,glocal.msg); if (glocal.userid > 0){ if (config.public_view && config.public_dir[0] != '\0' && strcmp(config.public_dir,"/")!=0){ // We have to validate that the directory exist string dirname = string_f("/projects/%s/public/%s",username.c_str(),config.public_dir); ENTRY entry; if (bo_writed_findentry (glocal.con,sessionid,dirname.c_str(),entry,true)==-1){ glocal.msg = MSG_U(E_UNKNOWNPUBDIR,"Unknown folder for public_dir"); }else if (!bolixo_isdir(entry.type)){ glocal.msg = MSG_U(E_PUBDIRNOTDIR,"public_dir is not a directory"); } } if (glocal.msg.size() == 0 && glocal.timezones.count(config.timezone)==0){ glocal.msg = MSG_U(E_IVLDTIMEZONE,"Invalid/Unknown time zone"); } if (glocal.msg.size() == 0){ if (sql_action("update config" " set lang='%s',dateformat=%u,public_view=%d,public_dir='%s',anon_messages=%u,timezone='%s'" " where userid=%u" ,config.lang,config.dateformat,config.public_view,config.public_dir ,config.anon_messages,config.timezone,glocal.userid)==-1){ glocal.msg = "Internal error, config table"; }else{ (glocal.con,sessionid,config.lang,config.dateformat,config.timezone); bo_writed_update_interest (config.public_view,glocal.userid,username); } } } if (glocal.msg.size() > 0){ rep_config_write (false,glocal.msg); }else{ rep_config_write (true,glocal.msg); } // sessionid user owner = success:b msg string msg; string username; unsigned userid = bo_writed_get_group_owner (glocal.con, sessionid, owner, username,msg); if (userid > 0){ bo_writed_interest_set (userid,user,msg); } if (msg.size() > 0){ rep_interest_set (false,msg); }else{ rep_interest_set (true,msg); } // sessionid user owner = success:b msg glocal string msg; string username; glocal unsigned userid = bo_writed_get_group_owner (glocal.con, sessionid, owner, username,glocal.msg); if (glocal.userid > 0){ glocal int check_id = fs_rec_getid ("select userid from id2name where name='%s'",user); if (glocal.check_id == -1){ glocal.msg = MSG_R(E_IVLDUSER); }else{ ("select check_userid from interests where userid=%u and check_userid=%d",glocal.userid,glocal.check_id); glocal.msg = MSG_U(E_USERNOTSET,"This user was not member of the interest set"); if (sql_action("delete from interests where userid=%u and check_userid=%d",glocal.userid,glocal.check_id)==-1){ glocal.msg = "Internal error, interests table"; } } } if (glocal.msg.size() > 0){ rep_interest_unset (false,glocal.msg); }else{ rep_interest_unset (true,glocal.msg); } glocal bool bdtrli=false; glocal bool bdusers=false; glocal bool sessiond=false; glocal bool keysd=false; glocal bool fsok= false; glocal bool publish_dbfiles = false; glocal bool publish_fsok = false; (*glocal.usq,"select count(*) from users"); glocal.bdusers=true; ("select count(*) from id2name"); glocal.bdtrli=true; (glocal.con); if (success) glocal.sessiond = true; (glocal.ctx.con_keys); glocal.keysd = lines.size() > 0; string testfile = string_f("/var/lib/bolixo/test-%ld",time(NULL)); (testfile,false); glocal.fsok = true; return 0; (glocal.ctx.con_publish,testfile); glocal.publish_fsok = fsok; glocal.publish_dbfiles = dbfiles; unlink (testfile.c_str()); rep_test (glocal.bdtrli,glocal.bdusers,glocal.sessiond,glocal.keysd,glocal.fsok,glocal.publish_dbfiles,glocal.publish_fsok); // msg = sign glocal bool success; glocal string msg; glocal string sign; (glocal.ctx.con_keys,-2,BOB_TYPE(msg,strlen(msg),false)); glocal.success = status == ERR_CODE_NONE ? true : false; glocal.msg = msg; glocal.sign = sign; rep_systemsign (glocal.success,glocal.msg,glocal.sign); // sessionid msg = success:b msg sign glocal bool success; glocal string msg; glocal string sign; string username; glocal unsigned userid = bo_writed_get_group_owner (glocal.con, sessionid, "", username,glocal.msg); if (glocal.userid > 0){ (glocal.ctx.con_keys,glocal.userid,BOB_TYPE(msg,strlen(msg),false)); glocal.success = status == ERR_CODE_NONE ? true : false; glocal.msg = msg; glocal.sign = sign; } rep_usersign (glocal.success,glocal.msg,glocal.sign); // nodename pubkey = success:b msg glocal const char *pubkey = pubkey; glocal const char *nodename = nodename; glocal string msg; ("select pub_key from nodes where nodename='%s'",nodename); if (sql_action("insert into nodes (nodename,pub_key) values ('%s','%s')",glocal.nodename,glocal.pubkey)==-1){ glocal.msg = "Internal error, table nodes"; } if (row[0] != NULL){ glocal.msg = "Already registered"; }else if (sql_action("update table nodes set pub_key='%s' where nodename='%s'",glocal.pubkey,glocal.nodename)==-1){ glocal.msg = "Internal error, table nodes"; } if (glocal.msg.size() > 0){ rep_registernode (false,glocal.msg); }else{ rep_registernode (true,""); } // sessionid user owner = success:b msg info:U{USERPUBLICINFO} string msg; unsigned userid = bo_writed_get_group_owner (glocal.con, sessionid, owner, msg); if (userid > 0){ if (sql_action("insert into userinfo (userid,publish,bosite_visible,fullname,address1,address2" ",city,zipcode,state,country,email,phone,fax,website,interest" ",publish_photo,publish_miniphoto)" " values " " (%u,%u,%u,'%s','%s','%s','%s','%s','%s','%s','%s','%s','%s','%s','%s',%d,%d)" " on duplicate key update" " publish=%d,bosite_visible=%d,fullname='%s',address1='%s',address2='%s'" ",city='%s',zipcode='%s',state='%s',country='%s',email='%s',phone='%s',fax='%s',website='%s',interest='%s'" ",publish_photo=%d,publish_miniphoto=%d" ,userid ,info.publish,info.bosite_visible,info.fullname,info.address1,info.address2 ,info.city,info.zipcode,info.state,info.country,info.email,info.phone ,info.fax,info.website,info.interest,info.photo,info.mini_photo ,info.publish,info.bosite_visible,info.fullname,info.address1,info.address2 ,info.city,info.zipcode,info.state,info.country,info.email,info.phone ,info.fax,info.website,info.interest,info.photo,info.mini_photo )==-1){ msg = "Internal error, updating userinfo table"; } } if (msg.size() > 0){ rep_info_write (false,msg); }else{ rep_info_write (true,""); } tlmp_error ("Client: Invalid command: %s\n",line); endclient = true; fflush (glocal.ctx.flog); } bool some_errors = false; if (fdpass_setcontrol(s,glocal.control,glocal.user)==-1){ some_errors = true; } if (!some_errors && s.is_ok()){ s.setrawmode(true); chmod (glocal.clientport.c_str()+5,0666); if (glocal.daemon){ daemon_init(glocal.pidfile,glocal.user); } glocal.ctx.flog = fopen (glocal.logfile,"a"); if (glocal.ctx.flog == NULL){ tlmp_error ("Can't open logfile %s (%s)\n",glocal.logfile,strerror(errno)); exit (-1); } open_instrument_file(); s.loop(); ret = 0; } fclose (glocal.ctx.flog); return ret; return glocal.ret; }