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