.
[sfinx.git] / sfinx / sfinx.C
blob90d2d10fe867b543bc244a0d0b36ec97fa3ad146
2  /*
3   *   Copyright (C) 2007, Rus V. Brushkoff, All rights reserved.
4   */
6 #include <sfinx.H>
7 #include <locale.h>
9 sfinx_app *sfinx;
11 // make preferences
12 void sfinx_app::dbopen()
14  dbname_ = "/usr/local/sfinx/sfinx.fdb";
15  dbuser_ = "sysdba";
16  dbpass_ = "harbour";
17  db_ = driver_->DatabaseFactory("", dbname_, dbuser_, dbpass_);
18  db_->Connect();
19  log("dbopen", "Connected to database %s", dbname_.c_str());
22 void sfinx_app::listen()
24  InetAddress addr((InetAddrValidator *)0);
25  log("sfinx:listen", "server listening at %d port", SFINX_PORT);
26  try {
27   sfinx_socket server(addr);
28   while(server.isPendingConnection()) {
29     faraon_session *faraon = new faraon_session(server, SFINX_MAX_PACKET_SIZE);
30     faraon->start();
31   }
32  }
33   catch(Socket *socket) {
34   
35     tpport_t port;
36     int err = socket->getErrorNumber();
37     cerr << "client socket error : ";
38     if (err == Socket::errBindingFailed) {
39       cerr << "bind failed; port busy, bye." << endl;
40       ::exit(-1);
41    }
42     IPV4Address saddr = socket->getPeer(&port);
43     const char *host;
44     if (!saddr.isInetAddress())
45      host = "localhost";
46     else
47      host = saddr.getHostname();
48     cerr << host << ":" << port << \
49       " failed : " << socket->getErrorString() << endl;
50  }
51    cerr << "listen terminated" << endl;
54 /*u32_t sfinx_app::get_object_slice(u32_t obj_type, u32_t obj_id)
56  sfinx_object_t o(obj_type, obj_id);
57  while (1) {
58    if (o.otype == SFINX_SLICE_OBJECT)
59      return o.oid;
60    if (!parent_object(o, &o))
61      bug();
62  }
63 }*/
65 sfinx_id_t sfinx_app::parent_slice_id(sfinx_id_t slice_id)
67  IBPP::Transaction tr = sfinx->driver_->TransactionFactory(sfinx->db_, IBPP::amRead,
68    IBPP::ilConcurrency, IBPP::lrWait);
69  tr->Start();
70  IBPP::Statement st = sfinx->driver_->StatementFactory(sfinx->db_, tr);
71  st->Prepare("select parent_id from slices where id = ?");
72  st->Set(1, (int64_t)slice_id);
73  st->Execute();
74  int64_t p_id = 0;
75  if (st->Fetch())
76    st->Get(1, &p_id);
77  else
78    debug("no parent for %lld slice !", slice_id);
79  tr->Commit();
80  return p_id;
83 string sfinx_app::slice_name(sfinx_id_t slice_id)
85  string name;
86  IBPP::Transaction tr = sfinx->driver_->TransactionFactory(sfinx->db_, IBPP::amRead,
87    IBPP::ilConcurrency, IBPP::lrWait);
88  tr->Start();
89  IBPP::Statement st = sfinx->driver_->StatementFactory(sfinx->db_, tr);
90  st->Prepare("select name from slices where id = ?");
91  st->Set(1, (int64_t)slice_id);
92  st->Execute();
93  while (st->Fetch()) {
94    st->Get(1, name);
95  }
96  tr->Commit();
97  return name;
100 string sfinx_app::slice_directory(sfinx_id_t slice_id)
102  string t;
103  IBPP::Transaction tr = sfinx->driver_->TransactionFactory(sfinx->db_, IBPP::amRead,
104    IBPP::ilConcurrency, IBPP::lrWait);
105  tr->Start();
106  IBPP::Statement st = sfinx->driver_->StatementFactory(sfinx->db_, tr);
107  st->Prepare("select directory from slices where id = ?");
108  st->Set(1, (int64_t)slice_id);
109  st->Execute();
110  while (st->Fetch()) {
111    st->Get(1, t);
113  tr->Commit();
114  return t;
117 bool sfinx_app::parent_object(sfinx_object_t &src, sfinx_object_t *dst)
119  switch (src.type) {
120    case SFINX_SLICE_OBJECT:
121      *dst = src;
122      dst->id = parent_slice_id(src.id);
123      return true;
124    default:
125      break;
127   return false;
130 // for objects other than slices if the mtag_id == SFINX_SLICE_OBJECT
131 // directory is the slice one
132 // for other mtag_id we look up in the hierarchy - all is created from the
133 // some slice
134 // TODO: think about editing object property (mtag_xxx) !
136 bool sfinx_app::set_sorted_path(sfinx_object_t &obj)
138  string path;
139  sfinx->files_module_conf.get(FILES_MODULE_SORTED_TREE_PATH, obj.path_name);
140  sfinx_object_t t = obj;
141  while (1) {
142    if (t.type == SFINX_SLICE_OBJECT) {
143      path.insert(0, "/" + slice_directory(t.id)); // TODO: handle spaces in names
144    if (t.id == 1) // root slice
145      break;
146   }
147    if (!parent_object(obj, &t))
148      return false;
149    obj = t;
151  obj.path_name += path;
152  return true;
155 // returns true on error
156 bool sfinx_app::sorted_path_mkdir(sfinx_object_t &obj)
158  if (set_sorted_path(obj))
159    return true;
160  return system(("mkdir -p " + obj.path_name).c_str());
163 int main(int argc, char **argv)
165  setlocale(LC_ALL, "");
166  char version[16];
167  sprintf(version, "v%0d.%0d.%0d", SFINX_VERSION_MAJOR, SFINX_VERSION_MINOR, SFINX_VERSION_PLEVEL);
168  sfinx = new sfinx_app(argc, argv, "sfinx", version,
169    "Harbour <Harbour@Sfinx.Od.UA>", "GPL");
170  try {
171    sfinx->dbopen();
172    sfinx->start_ui(); // start ui first
173    sfinx->listen();
175  catch(IBPP::Exception& e) {
176    log("IBPP::Exception", "%s", e.what());
177      if (sfinx->ui())
178        sfinx->ui()->alert("%s() Error !", e.Origin());
179  } 
180  return 0;
183 bool faraon_session::connect()
185  // send plain packet with daemon version
186  tx_elements.clear();
187  tx_elements.add(daemon_version);
188  // and available crypt types
189  tx_elements.add(packet_crypt_types);
190  // auth level
191  tx_elements.add(min_auth_levels);
192  // ÐÅÒÅÄÅÌÁÔØ Ó ÉÓÐÏÌØÚÏ×ÁÎÉÅÍ -lgcrypt
193  sfinx_8bit_vector_t md5_challenge(SFINX_MD5_SUM);
194  sfinx_crypter::get_random_bytes(md5_challenge, gcry_md_get_algo_dlen(GCRY_MD_MD5));
195  tx_elements.add(md5_challenge);
196  send_packet();
197  if (read_packet()) {
198    log("sfinx:connect", "Error reading faraon request");
199    return true;
202  // got SFINX_AUTH_REQUEST + auth data
203  // validate user_name/pass or rsa key
204  // ...
206  // send SFINX_ACCESS_GRANTED/SFINX_ACCESS_DENIED
207  tx_elements.clear();
208  sfinx_8bit_t access(SFINX_ACCESS_GRANTED);
209  access.set(0); // ÐÒÉÞÉÎÁ ÄÏÓÔÕÐÁ/ÏÔËÁÚÁ
210  tx_elements.add(access);
211  send_packet();
212  return false;
215 void faraon_session::run()
217  setError(1);
218  setNoDelay(1);
219  try {
220    if (connect())
221      return;
222    while(1) {
223     if (isPending(pendingInput, 10)) { // faraon'Ù ÐÒÏÓÀÔØ ...
224       if (process_requests()) {
225         log("sfinx:run", "Bad faraon request");
226         break;
227      }
228   }
229    Thread::sleep(10);
230   }
232  catch (Socket *s) {
233     tpport_t port;
234     InetAddress saddr = (InetAddress)getPeer(&port);
235     log("sfinx:run","Faraon client error at %s:%d - %s", saddr.getHostname(),
236             port, getErrorString());
238  catch (IBPP::Exception& e) {
239    log("sfinx:run", "%s", e.what());
240    sfinx->ui()->alert("%s() Error !", e.Origin());
242   final();
245 void faraon_session::get_slice(sfinx_id_t slice_id, sfinx_tid_t tid)
247  IBPP::Transaction tr = sfinx->driver_->TransactionFactory(sfinx->db_, IBPP::amRead,
248    IBPP::ilConcurrency, IBPP::lrWait);
249  tr->Start();
250  IBPP::Statement st = sfinx->driver_->StatementFactory(sfinx->db_, tr);
251  st->Prepare("select m.id, m.name, m.description, m.parent_id, (select name from slices where id = m.parent_id) as parent_name, m.ctime, m.etime, m.directory from slices m where m.id = ?");
252  st->Set(1, (int64_t)slice_id);
253  st->Execute();
254  string name, directory, description, parent_name;
255  int64_t id, parent_id;
256  sfinx_timestamp_t ctime, etime;
257  if (!st->Fetch())
258    return;
259  st->Get(1, &id);
260  st->Get(2, name);
261  st->Get(3, description);
262  st->Get(4, &parent_id);
263  if (!parent_id)
264    parent_name = "Dao";
265  else {
266    st->Get(5, parent_name);
268  st->Get(6, ctime);
269  st->Get(7, etime);
270  st->Get(8, directory);
271  sfinx_slice_t slice(id, name, directory, description, parent_name, parent_id, ctime, etime, tid);
272  tr->Commit();
273  send(slice);
276 void faraon_session::fill_files(sfinx_slice_t *slice)
280 void faraon_session::fill_notes(sfinx_slice_t *slice)
282  IBPP::Transaction tr = sfinx->driver_->TransactionFactory(sfinx->db_, IBPP::amRead,
283    IBPP::ilConcurrency, IBPP::lrWait);
284  tr->Start();
285  IBPP::Statement st = sfinx->driver_->StatementFactory(sfinx->db_, tr);
286  st->Prepare("select id, name, ctime, etime, mtag_id, mtag_type from notes where "
287    "mtag_slice_id = ? order by ctime desc");
288  st->Set(1, int64_t(slice->id));
289  st->Execute();
290  int64_t id, mtag_id;
291  int32 mtag_type;
292  sfinx_timestamp_t ctime, etime;
293  string name, description;
294  while (st->Fetch()) {
295    st->Get(1, &id);
296    st->Get(2, name);
297    // note description - ' for [[SFCN] mtag_name ]'
298    st->Get(3, ctime);
299    st->Get(4, etime);
300    st->Get(5, &mtag_id);
301    st->Get(6, &mtag_type);
302    sfinx_object_t o;
303    o.id = mtag_id;
304    o.type = mtag_type;
305    get_object(&o);
306    description = " for ";
307    description += tagtype2str(o);
308    description += " " + o.name;
309    if (o.description.size())
310      description += (" [ " + o.description + " ]");
311    sfinx_object_t note(SFINX_NOTE_OBJECT, (sfinx_id_t)id, slice->id, name.c_str(), ctime, etime);
312    note.description = description;
313    slice->add(note);
317 void faraon_session::add_slices_from_parent(sfinx_id_t parent_id, IBPP::Transaction tr, sfinx_slice_vector_t *slices,
318   u32_t obj_mask)
320  IBPP::Statement st = sfinx->driver_->StatementFactory(sfinx->db_, tr);
321  st->Prepare("select m.id, m.name, m.description, (select name from slices where id = "
322    "m.parent_id) as parent_name, m.ctime, m.etime, m.directory from slices m where parent_id = ? "
323    "order by ctime");
324  st->Set(1, (int64_t)parent_id);
325  st->Execute();
326  string name, description, parent_name, directory;
327  int64_t id;
328  sfinx_timestamp_t ctime, etime;
329  while (st->Fetch()) {
330   st->Get(1, &id);
331   st->Get(2, name);
332   st->Get(3, description);
333   if (!parent_id)
334     parent_name = "Dao";
335   else {
336     st->Get(4, parent_name);
338   st->Get(5, ctime);
339   st->Get(6, etime);
340   st->Get(7, directory);
341   sfinx_slice_t slice(id, name, directory, description, parent_name, parent_id, ctime, etime);
342   if (obj_mask & (1 << SFINX_FILE_OBJECT))
343     fill_files(&slice);
344   if (obj_mask & (1 << SFINX_NOTE_OBJECT))
345     fill_notes(&slice);
346   slices->add(slice);
347   add_slices_from_parent(id, tr, slices, obj_mask);
351 // ÐÅÒÅÄÁÅÔ ÄÅÒÅ×Ï ÓÌÁÊÓÏ× + ×ÌÏÖÅÎÎÙÅ ÏÂØÅËÔÙ, ÔÉРËÏÔÏÒÙÈ ÏÇÒÁÎÉÞÅΠÍÁÓËÏÊ
352 // ÄÅÒÅ×Ï ÐÅÒÅÄÁÅÔÓÑ ÏÔ ËÏÒÎÑ Ë ÌÉÓÔØÑÍ
353 // ÐÏËÁ ÐÒÉÍÅÎÉÍ application-side ÒÅËÕÒÓÉÀ
354 void faraon_session::get_objects(sfinx_tid_t reply_id, u32_t obj_mask)
356  sfinx_slice_vector_t slices(reply_id);
357  IBPP::Transaction tr = sfinx->driver_->TransactionFactory(sfinx->db_, IBPP::amRead,
358   IBPP::ilConcurrency, IBPP::lrWait);
359  tr->Start();
360  add_slices_from_parent(0, tr, &slices, obj_mask);
361  tr->Commit(); 
362  send(slices);
365 bool move(string &from, string &to)
367  debug("moving from %s -> %s", from.c_str(), to.c_str());
368  return system(("mv \"" + from + "\" \"" + to + "\"").c_str());
371 // TODO: make reply alert
372 void faraon_session::update_slice(sfinx_slice_t *slice)
374  IBPP::Transaction tr = sfinx->driver_->TransactionFactory(sfinx->db_, IBPP::amWrite,
375    IBPP::ilConcurrency, IBPP::lrWait);
376  tr->Start();
377  IBPP::Statement st = sfinx->driver_->StatementFactory(sfinx->db_, tr);
378  string old_dir = sfinx->slice_directory(slice->id);
379  if (old_dir != slice->directory()) {
380    string from, to;
381    sfinx_object_t o;
382    o.type = SFINX_SLICE_OBJECT;
383    o.id = slice->id;
384    sfinx->set_sorted_path(o);
385    from = o.path_name;
386    const char *p = strrchr(from.c_str(), '/');
387    if (!p)
388            bug();
389          char path[1024];
390          path[0] = 0;
391          strncat(path, from.c_str(), p - from.c_str());
392          to = path;
393          to += "/";
394          to += slice->directory();
395    move(from, to);
397   st->Prepare("update slices set etime = NULL, name = ?, description = ?, directory = ? where id = ?");
398   st->Set(1, slice->name());
399   st->Set(2, slice->description());
400   st->Set(3, slice->directory());
401   st->Set(4, (int64_t)slice->id);
402   st->Execute();
403   tr->Commit();
406 void faraon_session::new_slice(sfinx_slice_t *slice)
408  IBPP::Transaction tr = sfinx->driver_->TransactionFactory(sfinx->db_, IBPP::amWrite,
409    IBPP::ilConcurrency, IBPP::lrWait);
410  tr->Start();
411  IBPP::Statement st = sfinx->driver_->StatementFactory(sfinx->db_, tr);
412  st->Prepare("insert into slices (parent_id, name, description, directory) values  (?, ?, ?, ?)");
413  st->Set(1, (int64_t)slice->parent_id);
414  st->Set(2, slice->name());
415  st->Set(3, slice->description());
416  st->Set(4, slice->directory());
417  st->Execute();
418  tr->Commit();
421 void faraon_session::delete_slice_recursivly(sfinx_id_t slice_id)
423  IBPP::Transaction tr = sfinx->driver_->TransactionFactory(sfinx->db_, IBPP::amWrite,
424    IBPP::ilConcurrency, IBPP::lrWait);
425  tr->Start();
426  IBPP::Statement st = sfinx->driver_->StatementFactory(sfinx->db_, tr);
427  st->Prepare("select id from slices where parent_id = ?");
428  st->Set(1, (int64_t)slice_id);
429  st->Execute();
430  int32_t id;
431  while (st->Fetch()) {
432    st->Get(1, &id);
433    delete_slice_recursivly(id);
435  st->Prepare("delete from slices where id = ?");
436  st->Set(1, (int64_t)slice_id);
437  st->Execute();
438  tr->Commit(); // may be we need commit only at the end of the whole recursive deletion ?
441 void faraon_session::delete_slice_with_reattach(sfinx_id_t slice_id)
443  IBPP::Transaction tr = sfinx->driver_->TransactionFactory(sfinx->db_, IBPP::amWrite,
444    IBPP::ilConcurrency, IBPP::lrWait);
445  tr->Start();
446  IBPP::Statement st = sfinx->driver_->StatementFactory(sfinx->db_, tr);
447  st->Prepare("update slices set parent_id = (select parent_id from slices where id = ?) where parent_id = ?");
448  st->Set(1, (int64_t)slice_id);
449  st->Set(2, (int64_t)slice_id);
450  st->Execute();
451  st->Prepare("delete from slices where id = ?");
452  st->Set(1, (int64_t)slice_id);
453  st->Execute();
454  tr->Commit();
457 void faraon_session::delete_slice_assoc_data(sfinx_id_t slice_id, bool recursivly)
459  mark_files_unsorted(slice_id, recursivly, true);
460  // delete_notes();
461  // ...
464 void faraon_session::delete_slice_mark_data_unsorted(sfinx_id_t slice_id, bool recursivly)
466  mark_files_unsorted(slice_id, recursivly);
467  // mark_notes_unsorted();
468  // ...
471 void faraon_session::mark_files_unsorted(sfinx_id_t slice_id, bool recursivly, bool remove)
473  // delete from file_tags
474  IBPP::Transaction tr = sfinx->driver_->TransactionFactory(sfinx->db_, IBPP::amWrite,
475    IBPP::ilConcurrency, IBPP::lrWait);
476  tr->Start();
477  IBPP::Statement st = sfinx->driver_->StatementFactory(sfinx->db_, tr);
478  st->Prepare("delete from file_tags where obj_type = 1 and obj_id = ?");
479  st->Set(1, (int64_t)slice_id);
480  st->Execute();
481  // move to unsorted location
482  st->Prepare("select name from files where mtag_type = 1 and mtag_id = ?");
483  st->Set(1, (int64_t)slice_id);
484  st->Execute();
485  string udir, sdir;
486  sfinx_object_t o(SFINX_SLICE_OBJECT, slice_id, slice_id);
487  sfinx->set_sorted_path(o);
488  sdir = o.path_name + "/";
489  sfinx->files_module_conf.get(FILES_MODULE_UNSORTED_PATH, udir);
490  while(st->Fetch()) {
491    string name, from;
492    st->Get(1, name);
493    from = sdir + name;
494    if (remove)
495      unlink(from.c_str());
496    else
497      move(from, udir);
499  // delete from files
500  st->Prepare("delete from files where mtag_id = 1 and mtag_id = ?");
501  st->Set(1, (int64_t)slice_id);
502  st->Execute();
503  gen_desc_file(SFINX_SLICE_OBJECT, slice_id, slice_id);
504  if (recursivly) {
505    u32_t pid = sfinx->parent_slice_id(slice_id);
506    if (pid)
507      mark_files_unsorted(pid, true, remove);
509  tr->Commit(); 
512 // ÕÓÔÁÎÏ×ÌÅΠfile_id = mtag_slice_id É name
513 // ÎÕÖÎÏ ÎÁÊÔÉ ÆÁÊÌ Õ ËÏÔÏÒÏÇÏ ÉÌÉ parent ÉÌÉ ÒÏÄÎÏÊ ÓÌÁÊÓ ÔÁËÏÊ-ÖÅ
514 void faraon_session::mark_file_unsorted(sfinx_file_t *f, bool remove)
516  // delete from file_tags
517  IBPP::Transaction tr = sfinx->driver_->TransactionFactory(sfinx->db_, IBPP::amWrite,
518    IBPP::ilConcurrency, IBPP::lrWait);
519  tr->Start();
520  IBPP::Statement st = sfinx->driver_->StatementFactory(sfinx->db_, tr);
521  f->mtag_id = f->file_id;
522  f->mtag_type = SFINX_SLICE_OBJECT;
523  // get file_id
524  st->Prepare("select id from files where mtag_type = ? and mtag_id = ? and mtag_slice_id = ? and name = ?");
525  st->Set(1, (int32_t)f->mtag_type);
526  st->Set(2, (int64_t)f->mtag_id);
527  st->Set(3, (int64_t)f->mtag_slice_id);
528  st->Set(4, f->name);
529  int64_t file_id;
530  st->Execute();
531  if (!st->Fetch()) { // try to find parent id
532    bug();
533    return;
534  } else
535    st->Get(1, file_id);
536  st->Prepare("delete from file_tags where file_id = ?");
537  st->Set(1, file_id);
538  st->Execute();
539  // move to unsorted location
540  string udir, sdir;
541  sfinx_object_t o(f->mtag_type, f->mtag_id, f->mtag_slice_id);
542  sfinx->set_sorted_path(o);
543  sdir = o.path_name + "/";
544  sfinx->files_module_conf.get(FILES_MODULE_UNSORTED_PATH, udir);
545  string from = sdir + f->name;
546  if (remove)
547    unlink(from.c_str());
548  else
549    move(from, udir);
550  // delete from files
551  st->Prepare("delete from files where id = ?");
552  st->Set(1, file_id);
553  st->Execute();
554  tr->Commit();
555  gen_desc_file(f->mtag_type, f->mtag_id, f->mtag_slice_id);
558 void faraon_session::update_files_module_conf(sfinx_pair_vector_t *conf)
560  IBPP::Transaction tr = sfinx->driver_->TransactionFactory(sfinx->db_, IBPP::amWrite,
561    IBPP::ilConcurrency, IBPP::lrWait);
562  tr->Start();
563  IBPP::Statement st = sfinx->driver_->StatementFactory(sfinx->db_, tr);
564  st->Prepare("update files_module_conf set unsorted_files_path = ?, sorted_file_tree = ?, "
565    "desc_file_name = ?, desc_file_enable = ?");
566  string t;
567  conf->get(FILES_MODULE_UNSORTED_PATH, t);
568  st->Set(1, t);
569  conf->get(FILES_MODULE_SORTED_TREE_PATH, t);
570  st->Set(2, t);
571  conf->get(FILES_MODULE_DESC_FILE_NAME, t);
572  st->Set(3, t);
573  u32_t gen_desc_files;
574  conf->get(FILES_MODULE_DESC_FILE_ENABLE, &gen_desc_files);
575  st->Set(4, (int32_t)gen_desc_files);
576  st->Execute();
577  tr->Commit();
578  module_conf_request(SFINX_FILES_MODULE_CONF_REQUEST);
581 void sfinx_app::load_module_conf(u32_t id)
583  IBPP::Transaction tr = driver_->TransactionFactory(db_, IBPP::amRead,
584    IBPP::ilConcurrency, IBPP::lrWait);
585  tr->Start();
586  IBPP::Statement st = driver_->StatementFactory(db_, tr);
587  switch (id) {
588    case SFINX_FILES_MODULE_CONF_REQUEST:
589      st->Prepare("select unsorted_files_path, sorted_file_tree, desc_file_name, desc_file_enable from files_module_conf");
590      st->Execute();
591      files_module_conf.clear();
592      files_module_conf.tid(SFINX_FILES_MODULE_CONF);
593      while (st->Fetch()) {
594        string val;
595        st->Get(1, val);
596        files_module_conf.add(FILES_MODULE_UNSORTED_PATH, val);
597        st->Get(2, val);
598        files_module_conf.add(FILES_MODULE_SORTED_TREE_PATH, val);
599        st->Get(3, val);
600        files_module_conf.add(FILES_MODULE_DESC_FILE_NAME, val);
601        int32_t enable;
602        st->Get(4, &enable);
603        files_module_conf.add(FILES_MODULE_DESC_FILE_ENABLE, enable);
604     }
605      break;
606    default:
607      log("sfinx:load_module_conf", "Unknown module id - 0x%x", id);
608      break;
610  tr->Commit();
613 void faraon_session::module_conf_request(u32_t id)
615  switch (id) {
616    case SFINX_FILES_MODULE_CONF_REQUEST:
617      sfinx->load_module_conf(id);
618      send(sfinx->files_module_conf);
619      break;
620    default:
621      log("sfinx:module_conf_request", "Unknown module id - 0x%x", id);
622      break;
626 void faraon_session::relink_slice(sfinx_slice_t *slice)
628  // move directories
629  string from, to;
630  sfinx_object_t o_from(SFINX_SLICE_OBJECT, slice->id, slice->id);
631  sfinx->set_sorted_path(o_from);
632  from = o_from.path_name;
633  sfinx_object_t o_to(SFINX_SLICE_OBJECT, slice->parent_id, slice->parent_id);
634  sfinx->set_sorted_path(o_to);
635  to = o_to.path_name;
636  sfinx->sorted_path_mkdir(SFINX_SLICE_OBJECT, slice->parent_id, slice->parent_id);
637  move(from, to);
638 // relink
639  IBPP::Transaction tr = sfinx->driver_->TransactionFactory(sfinx->db_, IBPP::amWrite,
640    IBPP::ilConcurrency, IBPP::lrWait);
641  tr->Start();
642  IBPP::Statement st = sfinx->driver_->StatementFactory(sfinx->db_, tr);
643  st->Prepare("update slices set parent_id = ? where id = ?");
644  st->Set(1, (int64_t)slice->parent_id);
645  st->Set(2, (int64_t)slice->id);
646  st->Execute();
647  tr->Commit();
650 #include <dirent.h>
651 #include <errno.h>
652 #include <magic.h>
654 // × file_id ÈÒÁÎÉÔÓÑ id ÔÅËÕÝÅÊ ÄÉÒÅËÔÏÒÉÉ-ÓÌÁÊÓÁ × ËÏÔÏÒÏÊ ÎÁÈÏÄÉÍÓÑ/×ÙÂÒÁÌÉ
655 // × mtag_slice_id - parent_id ÄÉÒÅËÔÏÒÉÉ
656 // name - full dir path
657 // orig_name - dir entry
658 /*void faraon_session::send_dir(bool sorted, sfinx_file_t *f)
660  string dir;
661  sfinx->files_module_conf.get(sorted ? FILES_MODULE_SORTED_TREE_PATH : FILES_MODULE_UNSORTED_PATH, dir);
662  sfinx_files_vector_t files(sorted ? SFINX_FILES_MODULE_SORTED_TREE : SFINX_FILES_MODULE_UNSORTED_TREE);
663  if (f->name.size())
664    dir += f->name;
665  bool mime_detect = true;
666  // TODO: change mime_detect
667  //
668  //      0 - no detect
669  //      1 - deferable detect - send list firts, ÚÁÔÅÍ ÄÏÓÙÌÁÅÍ mimes ÞÁÓÔÑÍÉ
670  //      2 - full detect
672  struct magic_set *ms;
673  if (mime_detect) {
674    ms = magic_open(MAGIC_MIME | MAGIC_PRESERVE_ATIME | MAGIC_COMPRESS);
675    if (!ms)
676      mime_detect = false;
677    else {
678      if (magic_load(ms, NULL) == -1)
679        mime_detect = false;
680    }
682  struct dirent **namelist;
683  int n = scandir(dir.c_str(), &namelist, 0, alphasort);
684  if (n < 0) {
685    debug("%s scandir error: %s !", dir.c_str(), strerror(errno));
686    return;
688   sfinx_file_t file;
689   sfinx_progress_t prg("Processing files metadata ...");
690   prg.max(n);
691   send(prg);
692   u32_t p_id = 0;
693   if (sorted)
694     p_id = sfinx->parent_slice_id(f->file_id);
695   for (int i = 0; i < n; i++) {
696    if (prg.set(i, .5)) // ÛÁÇ 0.5%
697      send(prg);
698    file.clear();
699    if (!strcmp(namelist[i]->d_name, ".") || !strcmp(namelist[i]->d_name, ".."))
700      continue;
701    file.name = namelist[i]->d_name;
702    struct stat64 inode;
703    string full_path = dir + '/' + file.name;
704    if (stat64(full_path.c_str(), &inode))
705      debug("%s stat error: %s", full_path.c_str(), strerror(errno));
706    else
707      file.fsize = inode.st_size;
708    if (inode.st_mode & S_IFDIR)
709      file.is_directory = true;
710    file.etime.set(inode.st_ctime); // status changes
711    file.ctime.set(inode.st_mtime); // last modification
712    if (sorted) {
713      // set parent_id for up traverse
714      file.compressed_fsize = p_id;
715      if (file.is_directory) { // set dir id & dir parent_id from database
716       IBPP::Transaction tr = sfinx->driver_->TransactionFactory(sfinx->db_, IBPP::amRead,
717         IBPP::ilConcurrency, IBPP::lrWait);
718       tr->Start();
719       IBPP::Statement st = sfinx->driver_->StatementFactory(sfinx->db_, tr);
720       st->Prepare("select id from slices where directory = ? and parent_id = ?");
721       st->Set(1, file.name);
722       st->Set(2, (int64_t)f->file_id);
723       st->Execute();
724       if (!st->Fetch())
725         debug("*** no data for name %s and pid %d", file.name.c_str(), f->file_id);
726       else {
727         int64_t id;
728         st->Get(1, &id);
729         file.file_id = id;
730         file.mtag_id = f->file_id;
731         file.mtag_type = SFINX_SLICE_OBJECT;
732         // debug("for name %s id %d, pid %d", file.name.c_str(), id, f->file_id);
733      }
734       tr->Commit();
735      } else { // file - ÄÏÓÔÁÔÏÞÎÏ ÕÓÔÁÎÏ×ÉÔØ dir id, ÞÔÏ ÂÕÄÅÔ mtag_slice_id ÄÌÑ ÄÁÎÎÏÇÏ ÆÁÊÌÁ
736        file.file_id = f->file_id;
737        file.mtag_type = file.mtag_id = 0;
738     }
739    } else { // not sorted
740      file.file_id = 0;
741      file.compressed_fsize = file.mtag_type = file.mtag_id = 0;
742   }
743    if (mime_detect) {
744      const char *mimetype = magic_file(ms, full_path.c_str());
745      if (mimetype)
746        file.mimetype = mimetype;
747   } else {
748     if (file.is_directory)
749       file.mimetype = "inode/directory"; // "application/x-not-regular-file";
750     else
751       file.mimetype = "application/octet-stream";
752   }
753    free(namelist[i]);
754    files.add(file);
756   prg.end();
757   send(prg);
758   free(namelist);
759   send(files);
762 // may be use 7z.so ?
763 bool compress(string &infile, string *newname)
765  int res = system(("/usr/local/bin/sfinx_compress.sh " + infile).c_str());
766  if (res)
767    return true;
768  else
769    unlink(infile.c_str());
770  *newname = infile + ".7z";
771  return false;
774 // × ÄÉÒÅËÔÏÒÉÉ mtag_slice_id ÄÌÑ ×ÓÅÈ ÆÁÊÌÏ× ÓÏÚÄÁÅÍ description.txt ×ÉÄÁ:
776 //  slice_name - slice_decription
778 //  -----------------------------
780 // file1
782 // size1 - XXX
783 // csum1 - XXX
784 // compressed size1 - XXX
785 // compressed csum1 - XXX
786 // ctime1 - YYYY
787 // etime1 - YYYY
789 //  title1
791 //  authority1
793 //  description1
795 //  comments1
797 // -------------------------------
799 // file2 ...
801 bool faraon_session::gen_desc_file(sfinx_type_t obj_type, sfinx_id_t obj_id, sfinx_id_t slice_id)
803  string dir, fname;
804  // u32_t slice_id = sfinx->get_object_slice(obj_type, obj_id);
805  sfinx_object_t o(SFINX_SLICE_OBJECT, slice_id, slice_id);
806  sfinx->set_sorted_path(o);
807  dir = o.path_name;
808  sfinx->files_module_conf.get(FILES_MODULE_DESC_FILE_NAME, fname);
809  string desc_fname = dir + "/" + fname;
810  IBPP::Transaction tr = sfinx->driver_->TransactionFactory(sfinx->db_, IBPP::amRead,
811    IBPP::ilConcurrency, IBPP::lrWait);
812  tr->Start();
813  IBPP::Statement st = sfinx->driver_->StatementFactory(sfinx->db_, tr);
814  st->Prepare("select name, description, ctime, etime from slices where id = ?");
815  st->Set(1, (int64_t)slice_id);
816  st->Execute();
817  if (!st->Fetch()) { // hmm, no such slice ?
818    unlink(desc_fname.c_str());
819    return false;
820  } else {
821    ofstream f(desc_fname.c_str(), ios::out | ios::binary | ios::trunc);
822    if (!f)
823      return true;
824    string t;
825    st->Get(1, t); // name
826    f << endl;
827    f << t << " - ";
828    st->Get(2, t); // description
829    f << t << endl << endl;
830    // ctime/etime
831    IBPP::Timestamp xtime;
832    st->Get(3, xtime);
833          int year, month, day, hour, min, sec;
834          xtime.GetDate(year, month, day);
835          xtime.GetTime(hour, min, sec);
836          char buf[64];
837          sprintf(buf, "Slice created: %02d/%02d/%04d %02d:%02d:%02d", day, month, year, hour, min, sec);
838          f << buf << endl;
839          st->Get(4, xtime);
840          xtime.GetDate(year, month, day);
841          xtime.GetTime(hour, min, sec);
842          sprintf(buf, "Slice modified: %02d/%02d/%04d %02d:%02d:%02d", day, month, year, hour, min, sec);
843          f << buf << endl;       
844          f.close();
846  // store_compressed
847  // mimetype
848  st->Prepare("select id, name, title, authority, description, comments, ctime, etime, mtag_slice_id, "
849    "fsize, sha256, fsize_compressed, sha256_compressed, csum_last_checked, csum_valid, "
850    "store_in_sorted_location from files where mtag_type = 1 and mtag_id = ?");
851  st->Set(1, (int64_t)slice_id);
852  st->Execute();
853  while (st->Fetch()) {
854    ofstream f(desc_fname.c_str(), ios::out | ios::binary | ios::app);
855    if (!f)
856      return true;
857    int64_t fid;
858    st->Get(1, &fid);
859    string t;
860    f << endl << "-------------------------------------------------------------------" << endl << endl;
861    st->Get(2, t); // name
862    f << "Name: " << t << endl;
863    st->Get(3, t); // title
864    f << "Title: " << t << endl;   
865    st->Get(4, t); // authority
866    f << "Authority: " << t << endl;
867    st->Get(5, t); // description
868    f << "Description: " << t << endl;
869    st->Get(6, t); // comments
870    f << "Comments: " << t << endl;
871    IBPP::Timestamp xtime;
872    int year, month, day, hour, min, sec;
873    char buf[64];
874    st->Get(7, xtime);
875          xtime.GetDate(year, month, day);
876          xtime.GetTime(hour, min, sec);
877          sprintf(buf, "Entry created: %02d/%02d/%04d %02d:%02d:%02d", day, month, year, hour, min, sec);
878          f << buf << endl;
879    st->Get(8, xtime);
880          xtime.GetDate(year, month, day);
881          xtime.GetTime(hour, min, sec);
882          sprintf(buf, "Entry modifed: %02d/%02d/%04d %02d:%02d:%02d", day, month, year, hour, min, sec);
883          f << buf << endl;
884    int64_t fsize, compressed_fsize;
885    int64_t mtag_slice_id;
886    st->Get(9, mtag_slice_id);
887    st->Get(10, fsize);
888    f << "Size: " << fsize << endl;
889    st->Get(11, t); // csum
890    f << "Csum: " << t << endl;
891    st->Get(12, compressed_fsize);
892    f << "Compressed size: " << compressed_fsize << endl;
893    st->Get(13, t); // compressed_csum
894    f << "Compressed csum: " << t << endl;
895    // additional slices
896    IBPP::Statement st1 = sfinx->driver_->StatementFactory(sfinx->db_, tr);
897    st1->Prepare("select s.name, s.description from slices s, file_tags fs where fs.file_id = ? and fs.obj_id = s.id and fs.obj_type = 1");
898    st1->Set(1, (int64_t)fid);
899    st1->Execute();
900    if (st1->Fetch()) {
901      f << "Additional Slices: ";
902      bool comma = false;
903      while (st1->Fetch()) {
904        if (comma)
905          f << ", ";
906        st1->Get(1, t); // name
907        f << t << " [ ";
908        st1->Get(2, t); // description
909        f << t << " ]";
910        comma = true;
911      }
912        f << endl;
913    }
914    f.close();
916   tr->Commit();
917   return false;
920 // sets slice_id, name, description for type/id
921 // return true if success
922 bool faraon_session::get_object(sfinx_object_t *dst, sfinx_type_t obj_type, sfinx_id_t obj_id)
924  IBPP::Transaction tr = sfinx->driver_->TransactionFactory(sfinx->db_, IBPP::amRead,
925    IBPP::ilConcurrency, IBPP::lrWait);
926  tr->Start();
927  IBPP::Statement st = sfinx->driver_->StatementFactory(sfinx->db_, tr);
928  int64_t slice_id;
929  switch (obj_type) {
930    case SFINX_SLICE_OBJECT:
931      st->Prepare("select name, description from slices where id = ?");
932      st->Set(1, (int64_t)obj_id);
933      st->Execute();
934      if (!st->Fetch())
935        return false;
936      st->Get(1, dst->name);
937      st->Get(2, dst->description);
938      dst->slice_id = obj_id;
939      break;
940    case SFINX_FILE_OBJECT:
941      st->Prepare("select name, description, mtag_slice_id from files where id = ?");
942      st->Set(1, (int64_t)obj_id);
943      st->Execute();
944      if (!st->Fetch())
945        return false;
946      st->Get(1, dst->name);
947      st->Get(2, dst->description);
948      st->Get(3, &slice_id);
949      dst->slice_id = slice_id;
950      break;
951    case SFINX_NOTE_OBJECT:
952      st->Prepare("select name, mtag_slice_id, secured from notes where id = ?");
953      st->Set(1, (int64_t)obj_id);
954      st->Execute();
955      if (!st->Fetch())
956        return false;
957      st->Get(1, dst->name);
958      st->Get(2, &slice_id);
959      dst->slice_id = slice_id;     
960      //st->Get(3, dst->description); // set secured
961      break;
962    default:
963      return false;
965   tr->Commit();
966   return true;
969 // send note by id
970 void faraon_session::send_note(sfinx_note_t *n)
972  IBPP::Transaction tr = sfinx->driver_->TransactionFactory(sfinx->db_, IBPP::amRead,
973    IBPP::ilConcurrency, IBPP::lrWait);
974  tr->Start();
975  IBPP::Statement st = sfinx->driver_->StatementFactory(sfinx->db_, tr);
976  st->Prepare("select name, url, text, ctime, etime, mtag_type, mtag_id, secured from notes where id = ?");
977  st->Set(1, (int64_t)n->id);
978  st->Execute();
979  sfinx_note_t note(n->tid());
980  if (!st->Fetch()) {
981    sfinx_string_t alert(SFINX_ALERT);
982    alert.set("No such note in database !");
983    send(alert);
984    return;
985  } else {
986    st->Get(1, note.name);
987    st->Get(2, note.url);
988    st->Get(3, note.text);
989    st->Get(4, note.ctime);
990    st->Get(5, note.etime);
991    int32_t mtag_type;
992    st->Get(6, &mtag_type);
993    note.mtag.type = mtag_type;
994    int64_t mtag_id;
995    st->Get(7, &mtag_id);
996    note.mtag.id = mtag_id;
997    get_object(&note.mtag);
998    int16_t secured;
999    st->Get(8, &secured);
1000    note.secured = secured;
1002  // fill note tags
1003  st->Prepare("select obj_id, obj_type from note_tags where note_id = ?");
1004  st->Set(1, (int64_t)n->id);
1005  st->Execute();
1006  while (st->Fetch()) {
1007    int64_t tag_id;
1008    int32_t tag_type;
1009    st->Get(1, &tag_id);
1010    st->Get(2, &tag_type);
1011    // get tag by type and id
1012    sfinx_object_t o;
1013    o.type = tag_type;
1014    o.id = tag_id;
1015    if (get_object(&o))
1016      note.tags.push_back(o);
1018  tr->Commit();
1019  send(note);
1022 // send file by name & mtag
1023 void faraon_session::send_file(sfinx_file_t *f)
1025  //debug("name - %s, fid - %d, msid - %d", f->name.c_str(), f->file_id, f->mtag_slice_id);
1026  IBPP::Transaction tr = sfinx->driver_->TransactionFactory(sfinx->db_, IBPP::amRead,
1027    IBPP::ilConcurrency, IBPP::lrWait);
1028  tr->Start();
1029  IBPP::Statement st = sfinx->driver_->StatementFactory(sfinx->db_, tr);
1030  // store_compressed
1031  // mimetype
1032  // mtag_slice_id ?
1033  st->Prepare("select id, name, title, authority, description, comments, ctime, etime, "
1034    "fsize, sha256, fsize_compressed, sha256_compressed, csum_last_checked, csum_valid, "
1035    "store_in_sorted_location from files where mtag_type = 1 and mtag_id = ? and name = ?");
1036  st->Set(1, (int64_t)f->file_id);
1037  st->Set(2, f->name);
1038  st->Execute();
1039  int64_t fid;
1040  sfinx_file_t file(f->tid());
1041  if (!st->Fetch()) {
1042    sfinx_string_t alert(SFINX_ALERT);
1043    alert.set("No such file in database !");
1044    send(alert);
1045    return;
1046  } else {
1047    st->Get(1, &fid);
1048    file.file_id = fid;
1049    st->Get(2, file.name);
1050    st->Get(3, file.title);
1051    st->Get(4, file.authority);
1052    st->Get(5, file.description);
1053    st->Get(6, file.comments);
1054    st->Get(7, file.ctime);
1055    st->Get(8, file.etime);
1056    int64_t fsize, compressed_fsize;
1057    st->Get(9, fsize);
1058    st->Get(10, file.csum);
1059    st->Get(11, compressed_fsize);
1060    file.mtag_id = f->file_id;
1061    file.mtag_type = SFINX_SLICE_OBJECT;
1062    file.fsize = fsize;
1063    file.compressed_fsize = compressed_fsize;
1064    st->Get(12, file.compressed_csum);
1065    int32_t sorted_location;
1066    st->Get(15, &sorted_location);
1067    file.sorted_location = sorted_location;
1068    file.mimetype = "Not Set";
1070  // fill file slices
1071  st->Prepare("select obj_id, obj_type from file_tags where file_id = ?");
1072  st->Set(1, fid);
1073  st->Execute();
1074  while (st->Fetch()) {
1075    int64_t obj_id;
1076    int32_t obj_type;
1077    st->Get(1, &obj_id);
1078    st->Get(2, &obj_type);
1079    sfinx_object_t o(obj_id, obj_type, f->mtag_slice_id);
1080    file.objects.push_back(o);
1082  tr->Commit();
1083  send(file);
1086 void faraon_session::files_module_classify(sfinx_file_t *f)
1088  IBPP::Transaction tr;
1089  IBPP::Statement st;
1090  sfinx_string_t reply(SFINX_FILES_MODULE_CLASSIFY_REPLY);
1091  string compressed_name, sorted_location, dir, fname;
1092  sfinx_hash_t csum(GCRY_MD_SHA256), compressed_csum(GCRY_MD_SHA256);
1093  sfinx->files_module_conf.get(FILES_MODULE_UNSORTED_PATH, dir);
1094  fname = dir + "/" + f->name;
1095  // rename file
1096  if (f->name != f->orig_name) {
1097    if (rename((dir + "/" + f->orig_name).c_str(), (dir + "/" + f->name).c_str())) {
1098      reply.set("Error renaming file !");
1099      goto out;
1100    }
1102  // checksum file
1103  reply.set("Error calculating checksum for file !");
1104  if (f->generate_csum && csum.hash(fname))
1105    goto out;
1106  f->csum = csum.strvalue();
1107  if (f->sorted_location) {
1108    sfinx_object_t o(f->mtag_type, f->mtag_id, f->mtag_slice_id);
1109    reply.set("Error creating Sorted Location !");
1110    if (!sfinx->set_sorted_path(o))
1111      goto out;
1112    sorted_location = o.path_name;
1113    if (sfinx->sorted_path_mkdir(f->mtag_type, f->mtag_id, f->mtag_slice_id))
1114        goto out;
1115    reply.set("Error moving file to Sorted Location !");
1116    if (move(fname, sorted_location))
1117      goto out;
1119  fname = sorted_location + "/" + f->name;
1120  // get size
1121  struct stat64 inode;
1122  reply.set("Error getting file size !");
1123  if (stat64(fname.c_str(), &inode))
1124    goto out;
1125  else
1126    f->fsize = inode.st_size;
1127  // compress file
1128  if (f->store_compressed) {
1129    // check if file already compressed
1130    bool compressed = false;
1131    if (f->name.size() > 3) {
1132      string ext(f->name, f->name.size() - 3);
1133      if (ext == ".7z")
1134        compressed = true;
1135   }
1136    reply.set("Error compressing file !");
1137    if (!compressed) {
1138      if (compress(fname, &compressed_name))
1139        goto out;
1140      else
1141        f->name += ".7z";
1142    } else
1143        compressed_name = fname;
1144    reply.set("Error calculating checksum for compressed file !");
1145    if (f->generate_csum && compressed_csum.hash(compressed_name))
1146      goto out;
1147    f->compressed_csum = compressed_csum.strvalue();
1148    reply.set("Error getting compressed file size !");
1149    if (stat64(compressed_name.c_str(), &inode))
1150      goto out;
1151    else
1152      f->compressed_fsize = inode.st_size;
1154  // add to files
1155  tr = sfinx->driver_->TransactionFactory(sfinx->db_, IBPP::amWrite, IBPP::ilConcurrency, IBPP::lrWait);
1156  tr->Start();
1157  st = sfinx->driver_->StatementFactory(sfinx->db_, tr);
1158  st->Prepare("insert into files (name, title, authority, description, comments, mtag_id, mtag_type, fsize, "
1159    "sha256, fsize_compressed, sha256_compressed, store_in_sorted_location) values  (?, ?, ?, ?, ?, ?, ?, "
1160    "?, ?, ?, ?, ?)");
1161  st->Set(1, f->name);
1162  st->Set(2, f->title);
1163  st->Set(3, f->authority);
1164  st->Set(4, f->description);
1165  st->Set(5, f->comments);
1166  st->Set(6, (int64_t)f->mtag_id);
1167  st->Set(7, (int32_t)f->mtag_type);
1168  st->Set(8, (int64_t)f->fsize);
1169  st->Set(9, f->csum);
1170  st->Set(10, (int64_t)f->compressed_fsize);
1171  st->Set(11, f->compressed_csum);
1172  st->Set(12, f->sorted_location);
1173  st->Execute();
1175  st->Prepare("select id from files where name = ? and mtag_type = ? and mtag_id = ?");
1176  st->Set(1, f->name);
1177  st->Set(2, (int32_t)f->mtag_type);
1178  st->Set(3, (int64_t)f->mtag_id);
1179  st->Execute();
1180  int64_t file_id;
1181  if (!st->Fetch())
1182    bug();
1183  else {
1184    st->Get(1, &file_id);
1185 //   debug("added file has id - %d", file_id);
1187  // add to file_tags
1188  for (u32_t i = 0; i < f->objects.size(); i++) {
1189    st->Prepare("insert into file_tags (file_id, obj_id. obj_type) values (?, ?, ?)");
1190    st->Set(1, file_id);
1191    sfinx_object_t o = f->objects[i];
1192    st->Set(2, (int64_t)o.id);
1193    st->Set(3, (int32_t)o.type);
1194    st->Execute();
1196  tr->Commit();
1197  u32_t gen_desc_files;
1198  sfinx->files_module_conf.get(FILES_MODULE_DESC_FILE_ENABLE, &gen_desc_files);
1199  if (gen_desc_files) { // generate decription file
1200    reply.set("Error generating description file !");
1201    if (gen_desc_file(f->mtag_type, f->mtag_id, f->mtag_slice_id))
1202      goto out;
1204   reply.set(""); // No error
1205 out:
1206  send(reply);
1209 void faraon_session::notes_module_add(sfinx_note_t *n)
1211  IBPP::Transaction tr;
1212  IBPP::Statement st;
1213  sfinx_string_t reply(SFINX_NOTES_MODULE_ADD_REPLY);
1214  // add to files
1215  tr = sfinx->driver_->TransactionFactory(sfinx->db_, IBPP::amWrite, IBPP::ilConcurrency, IBPP::lrWait);
1216  tr->Start();
1217  st = sfinx->driver_->StatementFactory(sfinx->db_, tr);
1218  st->Prepare("insert into notes (name, text, url, mtag_id, mtag_type, mtag_slice_id) values (?, ?, ?, ?, ?, ?)");
1219  st->Set(1, n->name);
1220  st->Set(2, n->text);
1221  st->Set(3, n->url);
1222  st->Set(4, (int64_t)n->mtag.id);
1223  st->Set(5, (int32_t)n->mtag.type);
1224  st->Set(6, (int64_t)n->mtag.slice_id);
1225  st->Execute();
1226  // get new note id
1227  st->Prepare("select id from notes where name = ? and mtag_type = ? and mtag_id = ? and mtag_slice_id = ?");
1228  st->Set(1, n->name);
1229  st->Set(2, (int32_t)n->mtag.type);
1230  st->Set(3, (int64_t)n->mtag.id);
1231  st->Set(4, (int64_t)n->mtag.slice_id);
1232  st->Execute();
1233  int64_t note_id;
1234  if (!st->Fetch())
1235    bug();
1236  else {
1237    st->Get(1, &note_id);
1238 //   debug("added file has id - %d", file_id);
1240  // add note_tags
1241  for (u32_t i = 0; i < n->tags.size(); i++) {
1242    st->Prepare("insert into note_tags (note_id, obj_id, obj_type) values (?, ?, ?)");
1243    st->Set(1, note_id);
1244    st->Set(2, (int64_t)n->tags[i].id);
1245    st->Set(3, (int32_t)n->tags[i].type);
1246    st->Execute();
1248  tr->Commit();
1249  reply.set(""); // No error
1250  send(reply);
1253 bool faraon_session::get_file_by_id(sfinx_file_t *f)
1255  IBPP::Transaction tr = sfinx->driver_->TransactionFactory(sfinx->db_, IBPP::amRead,
1256    IBPP::ilConcurrency, IBPP::lrWait);
1257  tr->Start();
1258  IBPP::Statement st = sfinx->driver_->StatementFactory(sfinx->db_, tr);
1259  // store_compressed
1260  // mimetype
1261  st->Prepare("select name, title, authority, description, comments, ctime, etime, mtag_id, "
1262    "mtag_type, fsize, sha256, fsize_compressed, sha256_compressed, csum_last_checked, csum_valid, "
1263    "store_in_sorted_location, mtag_slice_id from files where id = ?");
1264  st->Set(1, (int64_t)f->file_id);
1265  st->Execute();
1266  if (!st->Fetch())
1267    return false;
1268  else {
1269    st->Get(1, f->name);
1270    st->Get(2, f->title);
1271    st->Get(3, f->authority);
1272    st->Get(4, f->description);
1273    st->Get(5, f->comments);
1274    st->Get(6, f->ctime);
1275    st->Get(7, f->etime);
1276    int64_t fsize, compressed_fsize, mtag_id, mtag_slice_id;
1277    int32_t mtag_type;
1278    st->Get(8, mtag_id);
1279    st->Get(9, mtag_type);
1280    st->Get(10, fsize);
1281    st->Get(11, f->csum);
1282    st->Get(12, compressed_fsize);
1283    f->mtag_id = mtag_id;
1284    f->mtag_type = mtag_type;
1285    f->fsize = fsize;
1286    f->compressed_fsize = compressed_fsize;
1287    st->Get(13, f->compressed_csum);
1288    int32_t sorted_location;
1289    st->Get(16, &sorted_location);
1290    f->sorted_location = sorted_location;
1291    st->Get(17, &mtag_slice_id);
1292    f->mtag_slice_id = mtag_slice_id;
1293    // st->Get(xxx, f->mimetype);
1295  // fill file tags
1296  f->objects.clear();
1297  st->Prepare("select obj_id, obj_type from file_tags where file_id = ?");
1298  st->Set(1, (int64_t)f->file_id);
1299  st->Execute();
1300  while (st->Fetch()) {
1301    int32_t object_type;
1302    int64_t object_id;
1303    st->Get(1, &object_id);
1304    st->Get(2, &object_type);
1305    sfinx_object_t o(object_type, object_id, f->mtag_slice_id);
1306    f->objects.push_back(o);
1308  tr->Commit();
1309  return true;
1312 void faraon_session::edit_file(sfinx_file_t *f)
1314  sfinx_file_t old_file;
1315  old_file.file_id = f->file_id;
1316  if (!get_file_by_id(&old_file))
1317    bug();
1318  IBPP::Transaction tr;
1319  IBPP::Statement st;
1320  sfinx_string_t reply(SFINX_FILES_MODULE_EDIT_REPLY);
1321  string compressed_name, sorted_location, dir, fname;
1322  if (f->sorted_location) {
1323    sfinx_object_t o(f->mtag_type, f->mtag_id, f->mtag_slice_id);
1324    sfinx->set_sorted_path(o);
1325    dir = o.path_name;
1326  } else
1327    sfinx->files_module_conf.get(FILES_MODULE_UNSORTED_PATH, dir);
1328  fname = dir + "/" + f->name;
1329  // rename file
1330  if (f->name != f->orig_name) {
1331    if (rename((dir + "/" + f->orig_name).c_str(), (dir + "/" + f->name).c_str())) {
1332      reply.set("Error renaming file !");
1333      goto out;
1334    }
1336  // add to files
1337  tr = sfinx->driver_->TransactionFactory(sfinx->db_, IBPP::amWrite, IBPP::ilConcurrency, IBPP::lrWait);
1338  tr->Start();
1339  st = sfinx->driver_->StatementFactory(sfinx->db_, tr);
1340  st->Prepare("update files set name = ?, title = ?, authority = ?, description = ?, comments = ?, "
1341    "mtag_id = ?, mtag_type = ?, fsize = ?, sha256 = ?, fsize_compressed = ?, sha256_compressed = ?, "
1342    "store_in_sorted_location = ? where id = ?");
1343  st->Set(1, f->name);
1344  st->Set(2, f->title);
1345  st->Set(3, f->authority);
1346  st->Set(4, f->description);
1347  st->Set(5, f->comments);
1348  st->Set(6, (int64_t)f->mtag_id);
1349  st->Set(7, (int32_t)f->mtag_type);
1350  st->Set(8, (int64_t)f->fsize);
1351  st->Set(9, f->csum);
1352  st->Set(10, (int64_t)f->compressed_fsize);
1353  st->Set(11, f->compressed_csum);
1354  st->Set(12, f->sorted_location);
1355  st->Set(13, (int64_t)f->file_id);
1356  st->Execute();
1358  // add to file_tags
1359  st->Prepare("delete from file_tags where file_id = ?");
1360  st->Set(1, (int64_t)f->file_id);
1361  st->Execute();
1362  for (u32_t i = 0; i < f->objects.size(); i++) {
1363    st->Prepare("insert into file_tags (file_id, obj_id, obj_type) values (?, ?, ?)");
1364    st->Set(1, (int64_t)f->file_id);
1365    sfinx_object_t o = f->objects[i];
1366    st->Set(2, (int64_t)o.id);
1367    st->Set(3, (int32_t)o.type);
1368    st->Execute();
1370  tr->Commit();
1371  u32_t gen_desc_files;
1372  sfinx->files_module_conf.get(FILES_MODULE_DESC_FILE_ENABLE, &gen_desc_files);
1373  if (gen_desc_files) { // generate decription file
1374    reply.set("Error generating description file !");
1375    if (gen_desc_file(f->mtag_type, f->mtag_id, f->mtag_slice_id))
1376      goto out;
1378   // move file
1379   if (old_file.sorted_location && f->sorted_location &&
1380     ((old_file.mtag_id != f->mtag_id) ||
1381     (old_file.mtag_type != f->mtag_type))) {
1382       sfinx_object_t o(old_file.mtag_type, old_file.mtag_id, old_file.mtag_slice_id);
1383       sfinx->set_sorted_path(o);
1384       string from = o.path_name + "/" + old_file.name;
1385       o.type = f->mtag_type;
1386       o.id = f->mtag_id;
1387       sfinx->set_sorted_path(o);
1388       string to = o.path_name + "/" + f->name;
1389       sfinx->sorted_path_mkdir(f->mtag_type, f->mtag_id, f->mtag_slice_id);
1390       move(from, to);
1391       // regen descs
1392       gen_desc_file(f->mtag_type, f->mtag_id, f->mtag_slice_id);
1393       gen_desc_file(old_file.mtag_type, old_file.mtag_id, old_file.mtag_slice_id);
1394   }
1395   reply.set(""); // No error
1396 out:
1397  send(reply);
1400 void faraon_session::search_in_files(string &pattern, sfinx_pair_vector_t *r)
1402  IBPP::Transaction tr = sfinx->driver_->TransactionFactory(sfinx->db_, IBPP::amRead,
1403    IBPP::ilConcurrency, IBPP::lrWait);
1404  tr->Start();
1405  IBPP::Statement st = sfinx->driver_->StatementFactory(sfinx->db_, tr),
1406    st1 = sfinx->driver_->StatementFactory(sfinx->db_, tr);
1407  st->Prepare("select id, name, title, authority, description, comments, ctime, etime, mtag_id, "
1408    "mtag_type, fsize, sha256, fsize_compressed, sha256_compressed, csum_last_checked, csum_valid, "
1409    "store_in_sorted_location, mtag_slice_id from files where name like ? or title like ? or authority like ? or "
1410    "description like ? or comments like ?");
1411  st->Set(1, pattern);
1412  st->Set(2, pattern);
1413  st->Set(3, pattern);
1414  st->Set(4, pattern);
1415  st->Set(5, pattern);
1416  st->Execute();
1417  int64_t rid = 0;
1418  while (st->Fetch()) {
1419    sfinx_file_t file;
1420    int64_t fid;
1421    st->Get(1, &fid);
1422    file.file_id = fid;
1423    st->Get(2, file.name);
1424    st->Get(3, file.title);
1425    st->Get(4, file.authority);
1426    st->Get(5, file.description);
1427    st->Get(6, file.comments);
1428    st->Get(7, file.ctime);
1429    st->Get(8, file.etime);
1430    int64_t fsize, compressed_fsize, mtag_id, mtag_slice_id;
1431    int32_t mtag_type;
1432    st->Get(9, mtag_id);
1433    st->Get(10, mtag_type);
1434    st->Get(11, fsize);
1435    st->Get(12, file.csum);
1436    st->Get(13, compressed_fsize);
1437    file.mtag_id = mtag_id;
1438    file.mtag_type = mtag_type;
1439    file.fsize = fsize;
1440    file.compressed_fsize = compressed_fsize;
1441    st->Get(14, file.compressed_csum);
1442    int32_t sorted_location;
1443    st->Get(17, &sorted_location);
1444    file.sorted_location = sorted_location;
1445    st->Get(18, &mtag_slice_id);
1446    file.mtag_slice_id = mtag_slice_id;
1447    file.mimetype = "Not Set";
1448    // fill file slices
1449    st1->Prepare("select obj_id, obj_type from file_tags where file_id = ?");
1450    st1->Set(1, fid);
1451    st1->Execute();
1452    while (st1->Fetch()) {
1453      int64_t obj_id;
1454      int32_t obj_type;
1455      st1->Get(1, &obj_id);
1456      st1->Get(2, &obj_type);
1457      sfinx_object_t o(obj_type, obj_id, file.mtag_slice_id);
1458      file.objects.push_back(o);
1459    }
1460    r->add(rid++, &file);
1462  tr->Commit();
1465 void faraon_session::search_query(sfinx_search_query_t *q)
1467  // debug("got pattern - %s", q->pattern.c_str());
1468  sfinx_pair_vector_t r(SFINX_ELEMENT_SEARCH_RESULT);
1469  // TODO: make threaded search, add sort rules
1470  string ptrn = '%' + q->pattern + '%';
1471  // search_in_slices(q->pattern, &r);
1472  search_in_files(ptrn, &r);
1473  // search_in_notes(q->pattern, &r);
1474  send(r);
1477 bool faraon_session::process_requests()
1479  if (read_packet()) {
1480    log("sfinx:process", "Error reading faraon request");
1481    return true;
1483  sfinx_t *el;
1484  string root;
1485  while ((el = rx_elements.next())) {
1486    switch (el->tid()) {
1487 //     case SFINX_NOTES_MODULE_EDIT:
1488 //       edit_note((sfinx_note_t *)el);
1489      case SFINX_NOTES_MODULE_EDIT_REQUEST:
1490        send_note((sfinx_note_t *)el);
1491        break;
1492      case SFINX_NOTES_MODULE_ADD:
1493        notes_module_add((sfinx_note_t *)el);
1494        break;
1495      case SFINX_FILES_MODULE_SORTED_UNLINK:
1496        mark_file_unsorted((sfinx_file_t *)el, true);
1497        break;
1498      case SFINX_FILES_MODULE_UNSORT:
1499        mark_file_unsorted((sfinx_file_t *)el);
1500        break;
1501      case SFINX_FILES_MODULE_UNLINK:
1502        unlink(((sfinx_string_t *)el)->c_str());
1503        break;
1504      case SFINX_ELEMENT_SEARCH_QUERY:
1505        search_query((sfinx_search_query_t *)el);
1506        break;
1507      case SFINX_FILES_MODULE_EDIT_FILE:
1508        edit_file((sfinx_file_t *)el);
1509        break;
1510      case SFINX_FILES_MODULE_EDIT_REQUEST:
1511        send_file((sfinx_file_t *)el);
1512        break;
1513      case SFINX_FILES_MODULE_CLASSIFY_REQUEST:
1514        files_module_classify((sfinx_file_t *)el);
1515        break;
1516 //     case SFINX_FILES_MODULE_SORTED_TREE_REQUEST:
1517 //       send_dir(true, (sfinx_file_t *)el);
1518 //       break;
1519      case SFINX_FILES_MODULE_UNSORTED_TREE_REQUEST:
1520 //       send_dir(false, (sfinx_file_t *)el);
1521        break;
1522      case SFINX_FILES_MODULE_CONF:
1523        update_files_module_conf((sfinx_pair_vector_t *)el);
1524        break;
1525      case SFINX_FILES_MODULE_CONF_REQUEST:
1526 //     case SFINX_XXX_MODULE_CONF_REQUEST:
1527        module_conf_request(el->tid());
1528        break;
1529      case SFINX_SLICE_RELINK:
1530        relink_slice((sfinx_slice_t *)el);
1531        break;
1532      case SFINX_DELETE_SLICE_ASSOC_DATA:
1533        delete_slice_assoc_data(((sfinx_32bit_t *)el)->get(), 0);
1534        break;
1535      case SFINX_DELETE_SLICE_ASSOC_DATA_RECURSIVLY:
1536        delete_slice_assoc_data(((sfinx_32bit_t *)el)->get(), 1);
1537        break;
1538      case SFINX_DELETE_SLICE_MARK_DATA_UNSORTED:
1539        delete_slice_mark_data_unsorted(((sfinx_32bit_t *)el)->get(), 0);
1540        break;
1541      case SFINX_DELETE_SLICE_MARK_DATA_UNSORTED_RECURSIVLY:
1542        delete_slice_mark_data_unsorted(((sfinx_32bit_t *)el)->get(), 1);
1543        break;
1544      case SFINX_DELETE_SLICE_WITH_REATTACH:
1545        delete_slice_with_reattach(((sfinx_32bit_t *)el)->get());
1546        break;
1547      case SFINX_DELETE_SLICE_RECURSIVLY:
1548        delete_slice_recursivly(((sfinx_32bit_t *)el)->get());
1549        break;
1550      case SFINX_NEW_SLICE:
1551        new_slice((sfinx_slice_t *)el);
1552        break;
1553      case SFINX_EDIT_SLICE:
1554        update_slice((sfinx_slice_t *)el);
1555        break;
1556      case SFINX_OBJECTS_TREE_REQUEST:
1557        get_objects(SFINX_OBJECTS_TREE, ((sfinx_32bit_t *)el)->get());
1558        break;
1559      case SFINX_EDIT_SLICE_REQUEST:
1560        get_slice(((sfinx_32bit_t *)el)->get(), SFINX_EDIT_SLICE);
1561        break;
1562      default:
1563        log("sfinx:process", "Unknown element %s (id - 0x%x)", sfinx_cmd2str(el->tid()), el->tid());
1564        break;
1565    }
1567  return false;