Ejemplo n.º 1
0
// handleEmailComment - handles an email received from from with subject subject and body body.
// Returns true if the mail was processed, else false.
// The email is considered to have been processed if it comments on an existing Consultation Note.
bool Notes_Logic::handleEmailComment (string from, string subject, string body)
{
  // Check whether the Consultation Notes Identifier in the subject exists in the notes database.
  // The CNID looks like: (CNID123456789)
  size_t pos = subject.find ("(CNID");
  if (pos == string::npos) return false;
  subject = subject.substr (pos + 5);
  pos = subject.find (")");
  if (pos == string::npos) return false;
  subject = subject.substr (0, pos);
  // Webserver request.
  Webserver_Request * request = (Webserver_Request *) webserver_request;
  // At this stage, the subject contains an identifier.
  // Check that the identifier is an existing Consultation Note.
  int identifier = convert_to_int (subject);
  Database_Notes database_notes (webserver_request);
  if (!database_notes.identifierExists (identifier)) return false;
  // Check that the from address of the email belongs to an existing user.
  // Or else use the obfuscated email address as the user name.
  string username;
  from = filter_string_extract_email (from);
  if (request->database_users()->emailExists (from)) {
    username = request->database_users()->getEmailToUser (from);
  } else {
    username = from;
    username = filter_string_str_replace ("@", " ", username);
    username = filter_string_str_replace (".", " ", username);
  }
  // Clean the email's body.
  string year = convert_to_string (filter_date_numerical_year (filter_date_seconds_since_epoch ()));
  string sender = Database_Config_General::getSiteMailName();
  body = filter_string_extract_body (body, year, sender);
  // Remove any new lines from the body. This cleans up the email considerably,
  // because some emails that get posted would otherwise look untidy,
  // when the many new lines take up a lot of space.
  body = filter_string_str_replace ("\n", " ", body);
  // Make comment on the consultation note.
  string sessionuser = request->session_logic ()->currentUser ();
  request->session_logic ()->setUsername (username);
  addComment (identifier, body);
  request->session_logic ()->setUsername (sessionuser);
  // Mail confirmation to the username.
  if (request->database_config_user()->getUserNotifyMeOfMyPosts (username)) {
    Database_Mail database_mail = Database_Mail (webserver_request);
    string subject = translate("Your comment was posted");
    subject.append (" [CNID");
    subject.append (convert_to_string (identifier));
    subject.append ("]");
    database_mail.send (username, subject, body);
  }
  // Log operation.
  Database_Logs::log ("Comment posted: " + body);
  // Job done.
  return true;
}
Ejemplo n.º 2
0
void Editor_Export::load (string html)
{
  // The web editor may insert non-breaking spaces. Convert them to normal ones.
  html = filter_string_str_replace (" ", " ", html);
  
  // The web editor produces <hr> following the HTML specs, but Bibledit needs
  // <hr/> for its XML parser.
  html = filter_string_str_replace ("<hr>", "<hr/>", html);
  
  // The user may add several spaces in sequence. Convert them to single spaces.
  html = filter_string_str_replace ("   ", " ", html);
  html = filter_string_str_replace ("  ", " ", html);
  
  // DOMDocument deals well with imperfect markup, but it may throw warnings to the default error handler.
  // Therefore keep the errors separate.
  xmlGenericErrorFunc handler = (xmlGenericErrorFunc) error_handler;
  initGenericErrorDefaultFunc (&handler);
  
  // To help loadHTML() process utf8 correctly, set the correct meta tag before any other text.
  /*
  string prefix =
  "<!DOCTYPE html>\n"
  "<html>\n"
  "<head>\n"
  "<meta http-equiv=\"content-type\" content=\"text/html; charset=UTF-8\">\n"
  "</head>\n"
  "<body>\n";
  string suffix =
  "\n"
  "</body>\n"
  "</html>\n";
  string xml = prefix + html + suffix;
  htmlParserCtxtPtr context = htmlNewParserCtxt();
  document = htmlCtxtReadMemory (context, xml.c_str(), xml.length(), "", "UTF-8", HTML_PARSE_RECOVER);
  htmlFreeParserCtxt (context);
   */

  // On Android, the HTML parser fails. It returns a NULL document.
  // Therefore use the XML parser instead of the HTML one.
  string prefix =
  "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
  "<html>\n"
  "<head>\n"
  "<meta http-equiv=\"content-type\" content=\"text/html; charset=UTF-8\"></meta>\n"
  "</head>\n"
  "<body>\n";
  string suffix =
  "\n"
  "</body>\n"
  "</html>\n";
  string xml = prefix + html + suffix;
  xmlParserCtxtPtr context = xmlNewParserCtxt();
  document = xmlCtxtReadMemory (context, xml.c_str(), xml.length(), "", "UTF-8", XML_PARSE_RECOVER);
  xmlFreeParserCtxt (context);
}
Ejemplo n.º 3
0
void Text_Text::paragraph (string text)
{
  if (thisline != "") {
    // The filter that converts from USFM to clear texts inserts some stuff
    // that's being removed here again, as not desirable in clear text.
    thisline = filter_string_str_replace (en_space(), " ", thisline);
    thisline = filter_string_str_replace ("  ", " ", thisline);
    output.push_back (thisline);
    thisline = "";
  }
  addtext (text);
}
Ejemplo n.º 4
0
void sword_logic_log (string message)
{
  // Remove less comely stuff, warnings, confusing information.
  message = filter_string_str_replace ("-=+*", "", message);
  message = filter_string_str_replace ("WARNING", "", message);
  message = filter_string_str_replace ("*+=-", "", message);
  message = filter_string_str_replace ("enable?", "", message);
  message = filter_string_str_replace ("[no]", "", message);
  // Clean message up.
  message = filter_string_trim (message);
  // Record in the journal.
  Database_Logs::log (message);
}
Ejemplo n.º 5
0
/*
 * The function returns the filename for a html file for a Bible.
 * $path    - The path where to store the files.
 * $book    - The book identifier.
 * $chapter - The chapter number.
 */
string filter_url_html_file_name_bible (string path, int book, int chapter)
{
  string filename;
  
  // If a path is given, prefix it.
  if (path != "") {
    filename = path + "/";
  }
  
  // No book ID given: Return the name for the index file for the Bible.
  if (book == 0) {
    filename += "index.html";
    return filename;
  }
  
  // Add the name for the book. No spaces.
  filename += filter_string_fill (convert_to_string (book), 2, '0');
  string sbook = Database_Books::getEnglishFromId (book);
  sbook = filter_string_str_replace (" ", "", sbook);
  filename += '-' + sbook;
  
  // Chapter given: Provide name for the chaper.
  if (chapter >= 0) {
    filename += '-' + filter_string_fill (convert_to_string (chapter), 3, '0');
  }
  
  filename += ".html";
  
  return filename;
}
Ejemplo n.º 6
0
// C++ equivalent for PHP's escapeshellarg function.
string filter_url_escape_shell_argument (string argument)
{
  argument = filter_string_str_replace ("'", "\\'", argument);
  argument.insert (0, "'");
  argument.append ("'");
  return argument;
}
Ejemplo n.º 7
0
string filter_passage_clean_passage (string text)
{
  // Trim text.
  text = filter_string_trim (text);
  // As references could be, e.g.: Genesis 10.2, or Genesis 10:2,
  // it needs to convert a the full stop and the colon to a space.
  text = filter_string_str_replace (".", " ", text);
  text = filter_string_str_replace (":", " ", text);
  // Change double spaces into single ones.
  text = filter_string_str_replace ("  ", " ", text);
  text = filter_string_str_replace ("  ", " ", text);
  // Trim again.
  text = filter_string_trim (text);
  // Result.
  return text;
}
Ejemplo n.º 8
0
void Database_Logs::log (string description, int level)
{
  // No new lines.
  description = filter_string_str_replace ("\n", " ", description);
  // Discard empty line.
  if (filter_string_trim (description).empty()) return;
  // Truncate long entry.
  int length = description.length ();
  if (length > 1000) {
    description.erase (1000);
    description.append ("... This entry was too large and has been truncated: " + convert_to_string (length) + " bytes");
  }
  // Save this logbook entry to a filename with seconds and microseconds.
  string seconds = convert_to_string (filter_date_seconds_since_epoch ());
  string time = seconds + filter_string_fill (convert_to_string (filter_date_numerical_microseconds ()), 8, '0');
  string file = filter_url_create_path (folder (), time);
  // The microseconds granularity depends on the platform.
  // On Windows it is lower than on Linux.
  // There may be the rare case of more than one entry per file.
  // Append the data so it won't overwrite an earlier entry.
  if (file_exists (file)) {
    description.insert (0, " | ");
  } else {
    description.insert (0, convert_to_string (level) + " " + seconds + " ");
  }
  filter_url_file_put_contents_append (file, description);
  // Delay to cover for lower usec granularity on Windows.
  if (config_logic_windows ()) {
    this_thread::sleep_for (chrono::milliseconds (1));
  }
}
Ejemplo n.º 9
0
// Return the raw data of default versification system $name.
string versification_logic_data (string name)
{
  name = filter_string_str_replace (" ", "_", name);
  name.append (".txt");
  string file = filter_url_create_root_path ("versification", name);
  return filter_url_file_get_contents (file);
}
Ejemplo n.º 10
0
string edit_load (void * webserver_request)
{
  Webserver_Request * request = (Webserver_Request *) webserver_request;
  
  string bible = request->query ["bible"];
  int book = convert_to_int (request->query ["book"]);
  int chapter = convert_to_int (request->query ["chapter"]);
  
  // Store a copy of the USFM loaded in the editor for later reference.
  storeLoadedUsfm (webserver_request, bible, book, chapter, "edit");
  
  string stylesheet = request->database_config_user()->getStylesheet ();
  
  string usfm = request->database_bibles()->getChapter (bible, book, chapter);
  
  Editor_Usfm2Html editor_usfm2html;
  editor_usfm2html.load (usfm);
  editor_usfm2html.stylesheet (stylesheet);
  editor_usfm2html.run ();
  
  string html = editor_usfm2html.get ();
  
  // To make editing empty verses easier, convert spaces to non-breaking spaces, so they appear in the editor.
  if (usfm_contains_empty_verses (usfm)) {
    string search = "<span> </span>";
    string replace = "<span>" + unicode_non_breaking_space_entity () + "</span>";
    html = filter_string_str_replace (search, replace, html);
  }
  
  string user = request->session_logic ()->currentUser ();
  bool write = access_bible_book_write (webserver_request, user, bible, book);
  
  return Checksum_Logic::send (html, write);
}
Ejemplo n.º 11
0
// This function removes the notes from the USFM.
// $usfm: Where to extract from.
// $markers: Array of markers surrounding the notes.
// It returns the USFM without the notes.
string usfm_remove_notes (string usfm, const vector <string> & markers)
{
  vector <UsfmNote> notes = usfm_extract_notes (usfm, markers);
  for (auto note : notes) {
    string search = note.data;
    usfm = filter_string_str_replace (search, "", usfm);
  }
  return usfm;
}
Ejemplo n.º 12
0
void Styles_Css::customize (const string& bible)
{
  string cls = Filter_Css::getClass (bible);
  string font = Fonts_Logic::getTextFont (bible);
  bool uploaded_font = Fonts_Logic::fontExists (font);
  font = Fonts_Logic::getFontPath (font);
  int direction = Database_Config_Bible::getTextDirection (bible);
  string css = Filter_Css::getCss (cls, font, direction);
  if (uploaded_font) css = filter_string_str_replace ("../fonts/", "", css);
  code.push_back (css);
}
Ejemplo n.º 13
0
string Editor_Html2Usfm::cleanUSFM (string usfm)
{
  // Replace a double space after a note opener.
  for (string noteOpener : noteOpeners) {
    string opener = usfm_get_opening_usfm (noteOpener);
    usfm = filter_string_str_replace (opener + " ", opener, usfm);
  }

  // Done.
  return usfm;
}
Ejemplo n.º 14
0
// Returns the string $code as an array alternating between marker and text.
// Example, input is:   \id GEN
//                      \c 10
//             ...
// Output would be:     array ("\id ", "GEN", "\c ", "10", ...)
// If $code does not start with a marker, this becomes visible in the output too.
vector <string> usfm_get_markers_and_text (string code)
{
  vector <string> markers_and_text;
  code = filter_string_str_replace ("\n\\", "\\", code); // New line followed by backslash: leave new line out.
  code = filter_string_str_replace ("\n", " ", code); // New line only: change to space, according to the USFM specification.
  // No removal of double spaces, because it would remove an opening marker (which already has its own space), followed by a space.
  code = filter_string_trim (code);
  while (!code.empty ()) {
    size_t pos = code.find ("\\");
    if (pos == 0) {
      // Marker found.
      // The marker ends
      // - after the first space, or
      // - after the first asterisk (*), or
      // - at the first backslash (\), or
      // - at the end of the string,
      // whichever comes first.
      vector <size_t> positions;
      pos = code.find (" ");
      if (pos != string::npos) positions.push_back (pos + 1);
      pos = code.find ("*");
      if (pos != string::npos) positions.push_back (pos + 1);
      pos = code.find ("\\", 1);
      if (pos != string::npos) positions.push_back (pos);
      positions.push_back (code.length());
      sort (positions.begin (), positions.end());
      pos = positions[0];
      string marker = code.substr (0, pos);
      markers_and_text.push_back (marker);
      code = code.substr (pos);
    } else {
      // Text found. It ends at the next backslash or at the end of the string.
      pos = code.find ("\\");
      if (pos == string::npos) pos = code.length();
      string text = code.substr (0, pos);
      markers_and_text.push_back (text);
      code = code.substr (pos);
    }
  }
  return markers_and_text;
}
Ejemplo n.º 15
0
void Editor_Html2Usfm::load (string html)
{
  // The web editor may insert non-breaking spaces. Convert them to normal ones.
  html = filter_string_str_replace (non_breaking_space_entity (), " ", html);
  
  // The web editor produces <hr> and other elements following the HTML specs,
  // but Bibledit's XML parser needs <hr/> and similar elements.
  html = html2xml (html);
  
  // The user may add several spaces in sequence. Convert them to single spaces.
  html = filter_string_str_replace ("   ", " ", html);
  html = filter_string_str_replace ("  ", " ", html);
  
  string xml = "<body>\n" + html + "\n</body>";
  // Parse document with important option, so it parses the white space in the following:
  //   <node> </node>
  // This is significant for, for example, the space after verse numbers, among others.
  xml_parse_result result = document.load_string (xml.c_str(), parse_ws_pcdata_single);
  // Log parsing errors.
  pugixml_utils_error_logger (&result, xml);
}
Ejemplo n.º 16
0
void Checks_Sentences::enterNames (string names_in)
{
  names.clear ();
  names_in = filter_string_str_replace ("\n", " ", names_in);
  vector <string> names2 = filter_string_explode (names_in, ' ');
  for (auto name : names2) {
    if (name != "") {
      // Limit the length to the left of the suffix in the test.
      name = unicode_string_substr (name, 0, 11);
      names.push_back (name);
    }
  }
}
Ejemplo n.º 17
0
string index_listing (void * webserver_request, string url)
{
    string page;
    page = Assets_Page::header ("Bibledit", webserver_request);
    // No breadcrumbs because the user can arrive here from more than one place.
    Assets_View view;
    url = filter_url_urldecode (url);
    url = filter_url_create_path ("", url);
    url = filter_string_str_replace ("\\", "/", url);
    view.set_variable ("url", url);
    string parent = filter_url_dirname_web (url);
    if (parent.length () > 1) {
        view.enable_zone ("parent");
        view.set_variable ("parent", parent);
    }
    string directory = filter_url_create_root_path (url);
    if (!file_or_dir_exists (directory) || filter_url_is_dir (directory)) {
        vector <string> files = filter_url_scandir (directory);
        for (auto & file : files) {
            string path = filter_url_create_path (directory, file);
            string line;
            line.append ("<tr>");
            line.append ("<td>");
            line.append ("<a href=\"" + filter_url_create_path (url, file) + "\">");
            line.append (file);
            line.append ("</a>");
            line.append ("</td>");
            line.append ("<td>");
            if (!filter_url_is_dir (path)) {
                line.append (convert_to_string (filter_url_filesize (path)));
            }
            line.append ("</td>");
            line.append ("</tr>");
            file = line;
        }
        string listing = filter_string_implode (files, "\n");
        if (listing.empty ()) listing = translate ("No files in this folder");
        else {
            listing.insert (0, "<table>");
            listing.append ("</table>");
        }
        view.set_variable ("listing", listing);
    } else {
        string filename = filter_url_create_root_path (url);
        return filter_url_file_get_contents (filename);
    }
    page += view.render ("index", "listing");
    page += Assets_Page::footer ();
    return page;
}
Ejemplo n.º 18
0
// Prepares a sample Bible.
// The output of this is supposed to be manually put into the source tree, folder "samples".
// This will be used to quickly create a sample Bible, that is fast, even on mobile devices.
void demo_prepare_sample_bible ()
{
  Database_Bibles database_bibles;
  // Remove the Bible to remove all stuff that might have been in it.
  database_bibles.deleteBible (demo_sample_bible_name ());
  search_logic_delete_bible (demo_sample_bible_name ());
  // Create a new one.
  database_bibles.createBible (demo_sample_bible_name ());
  // Location of the USFM files for the sample Bible.
  string directory = filter_url_create_root_path ("demo");
  vector <string> files = filter_url_scandir (directory);
  for (auto file : files) {
    // Only process the USFM files.
    if (filter_url_get_extension (file) == "usfm") {
      cout << file << endl;
      // Read the USFM.
      file = filter_url_create_path (directory, file);
      string usfm = filter_url_file_get_contents (file);
      usfm = filter_string_str_replace ("  ", " ", usfm);
      // Import the USFM into the Bible.
      vector <BookChapterData> book_chapter_data = usfm_import (usfm, styles_logic_standard_sheet ());
      for (auto data : book_chapter_data) {
        Bible_Logic::storeChapter (demo_sample_bible_name (), data.book, data.chapter, data.data);
      }
    }
  }
  // Clean the destination location for the Bible.
  string destination = sample_bible_bible_path ();
  filter_url_rmdir (destination);
  // Copy the Bible data to the destination.
  string source = database_bibles.bibleFolder (demo_sample_bible_name ());
  filter_url_dir_cp (source, destination);
  // Clean the destination location for the Bible search index.
  destination = sample_bible_index_path ();
  filter_url_rmdir (destination);
  // Create destination location.
  filter_url_mkdir (destination);
  // Copy the index files over to the destination.
  source = search_logic_index_folder ();
  files = filter_url_scandir (source);
  for (auto file : files) {
    if (file.find (demo_sample_bible_name ()) != string::npos) {
      string source_file = filter_url_create_path (source, file);
      string destination_file = filter_url_create_path (destination, file);
      filter_url_file_cp (source_file, destination_file);
    }
  }
}
Ejemplo n.º 19
0
// Get the names of the available default versification systems that come with Bibledit.
vector <string> versification_logic_names ()
{
  vector <string> names;

  string directory = filter_url_create_root_path ("versification");
  vector <string> files = filter_url_scandir (directory);
  for (auto file : files) {
    if (filter_url_get_extension (file) == "txt") {
      // Remove the dot and extension.
      file = file.substr (0, file.length () - 4);
      // Change underscores to spaces for the names.
      file = filter_string_str_replace ("_", " ", file);
      names.push_back (file);
    }
  }
  
  return names;
}
Ejemplo n.º 20
0
// Searches the text of the Bibles.
// Returns an array with matching passages.
// $search: Contains the text to search for.
// $bibles: Array of Bible names to search in.
vector <Passage> search_logic_search_text (string search, vector <string> bibles)
{
  vector <Passage> passages;
  
  if (search == "") return passages;
  
  search = unicode_string_casefold (search);
  search = filter_string_str_replace (",", "", search);
  
  Database_Bibles database_bibles;
  for (auto bible : bibles) {
    vector <int> books = database_bibles.getBooks (bible);
    for (auto book : books) {
      vector <int> chapters = database_bibles.getChapters (bible, book);
      for (auto chapter : chapters) {
        string path = search_logic_chapter_file (bible, book, chapter);
        string index = filter_url_file_get_contents (path);
        if (index.find (search) != string::npos) {
          vector <string> lines = filter_string_explode (index, '\n');
          int index_verse = 0;
          bool read_index_verse = false;
          int index_item = 0;
          for (auto & line : lines) {
            if (read_index_verse) {
              index_verse = convert_to_int (line);
              read_index_verse = false;
            } else if (line == search_logic_verse_separator ()) {
              read_index_verse = true;
              index_item = 0;
            } else if (line == search_logic_index_separator ()) {
              index_item++;
            } else if (index_item == PLAIN_LOWER) {
              if (line.find (search) != string::npos) {
                passages.push_back (Passage (bible, book, chapter, convert_to_string (index_verse)));
              }
            }
          }
        }
      }
    }
  }

  return passages;
}
Ejemplo n.º 21
0
string administration_timezone (void * webserver_request)
{
  Webserver_Request * request = (Webserver_Request *) webserver_request;

  string page;

  Assets_Header header = Assets_Header (translate("Timezone"), webserver_request);
  header.addBreadCrumb (menu_logic_settings_menu (), menu_logic_settings_text ());
  page = header.run ();

  Assets_View view;

  string success;
  string error;
  if (request->post.count ("submit")) {
    string input = request->post ["timezone"];
    input = filter_string_str_replace ("UTC", "", input);
    int timezone = convert_to_int (input);
    bool clipped = false;
    if (timezone < MINIMUM_TIMEZONE) {
      timezone = MINIMUM_TIMEZONE;
      clipped = true;
    }
    if (timezone > MAXIMUM_TIMEZONE) {
      timezone = MAXIMUM_TIMEZONE;
      clipped = true;
    }
    if (clipped) error = translate ("The timezone was clipped");
    Database_Config_General::setTimezone (timezone);
    success = translate ("The timezone was saved");
  }

  int timezone = Database_Config_General::getTimezone();
  view.set_variable ("timezone", convert_to_string (timezone));
  view.set_variable ("success", success);
  view.set_variable ("error", error);
  
  page += view.render ("administration", "timezone");

  page += Assets_Page::footer ();

  return page;
}
Ejemplo n.º 22
0
string render_journal_entry (string entry)
{
  // Remove the user's level.
  entry.erase (0, 2);
  // Extract and remove the seconds since the Unix epoch.
  time_t seconds = convert_to_int (entry);
  entry.erase (0, 11);
  // Localize the seconds.
  seconds = filter_date_local_seconds (seconds);
  // Sanitize HTML.
  entry = filter_string_sanitize_html (entry);
  // Convert \n to <br>
  entry = filter_string_str_replace ("\n", "<br>", entry);
  // Convert the seconds into a human readable time.
  string timestamp = filter_string_fill (convert_to_string (filter_date_numerical_hour (seconds)), 2, '0');
  timestamp.append (":");
  timestamp.append (filter_string_fill (convert_to_string (filter_date_numerical_minute (seconds)), 2, '0'));
  timestamp.append (":");
  timestamp.append (filter_string_fill (convert_to_string (filter_date_numerical_second (seconds)), 2, '0'));
  // Done.
  return timestamp + " | " + entry;
}
Ejemplo n.º 23
0
string editverse_load (void * webserver_request)
{
  Webserver_Request * request = (Webserver_Request *) webserver_request;
  
  string bible = request->query ["bible"];
  int book = convert_to_int (request->query ["book"]);
  int chapter = convert_to_int (request->query ["chapter"]);
  int verse = convert_to_int (request->query ["verse"]);
  
  string usfm = request->database_bibles()->getChapter (bible, book, chapter);
  usfm = usfm_get_verse_text (usfm, verse);
  
  usfm = filter_string_str_replace ("\n", "<br>", usfm);
  string chapter_verse_text;
  string needle = "\\c";
  if (verse) needle = "\\v";
  size_t pos = usfm.find (needle);
  if (pos != string::npos) {
    if (pos < 2) {
      usfm.erase (0, pos + 2);
      usfm = filter_string_trim (usfm);
      chapter_verse_text = usfm_peek_verse_number (usfm);
      usfm.erase (0, chapter_verse_text.length ());
      usfm = filter_string_trim (usfm);
    }
  }
  usfm.insert (0, "<span contenteditable=\"true\">");
  usfm.append ("</span>");
  if (!chapter_verse_text.empty ()) {
    string spacer;
    if (verse) spacer = " ";
    usfm.insert (0, "<span " + filter_css_grey_background () + ">" + needle + " " + chapter_verse_text + spacer + "</span>");
  }
  
  string user = request->session_logic ()->currentUser ();
  bool write = access_bible_book_write (webserver_request, user, bible, book);
  
  return Checksum_Logic::send (usfm, write);
}
Ejemplo n.º 24
0
// Create a consultation note.
// $bible: The notes's Bible.
// $book, $chapter, $verse: The note's passage.
// $summary: The note's summary.
// $contents: The note's contents.
// $raw: Import $contents as it is.
// It returns the $identifier of this new note.
int Notes_Logic::createNote (string bible, int book, int chapter, int verse, string summary, string contents, bool raw)
{
  summary = filter_string_str_replace ("\n", "", summary);
  Database_Notes database_notes (webserver_request);
  int note_id = database_notes.storeNewNote (bible, book, chapter, verse, summary, contents, raw);
  if (client_logic_client_enabled ()) {
    // Client: record the action in the database.
    Database_NoteActions database_noteactions;
    Webserver_Request * request = (Webserver_Request *) webserver_request;
    database_noteactions.record (request->session_logic()->currentUser (), note_id, Sync_Logic::notes_put_create_initiate, "");
    database_noteactions.record (request->session_logic()->currentUser (), note_id, Sync_Logic::notes_put_summary, "");
    // The contents to submit to the server, take it from the database, as it was updated in the logic above.
    database_noteactions.record (request->session_logic()->currentUser (), note_id, Sync_Logic::notes_put_contents, database_notes.getContents (note_id));
    database_noteactions.record (request->session_logic()->currentUser (), note_id, Sync_Logic::notes_put_bible, "");
    database_noteactions.record (request->session_logic()->currentUser (), note_id, Sync_Logic::notes_put_passages, "");
    database_noteactions.record (request->session_logic()->currentUser (), note_id, Sync_Logic::notes_put_create_complete, "");
  } else {
    // Server: do the notifications.
    handlerNewNote (note_id);
  }
  return note_id;
}
Ejemplo n.º 25
0
string Editor_Export::cleanUSFM (string usfm)
{
  // The user may accidentally omit or erase the note caller.
  // The note caller is one character that immediately follows the note opener.
  // E.g.: \f + ...\f*.
  // Check for missing note caller, and if it's not there, add the default "+".
  // Also replace a double space after a note opener.
  for (string noteOpener : noteOpeners) {
    string opener = usfm_get_opening_usfm (noteOpener);
    usfm = filter_string_str_replace (opener + " ", opener, usfm);
    size_t pos = unicode_string_strpos (usfm, opener);
    while (pos != string::npos) {
      bool isClean = true;

      // Check that the character that follows the note opener is a non-space.
      size_t pos2 = pos + unicode_string_length (opener);
      string character = unicode_string_substr (usfm, pos2, 1);
      if (character == " ") isClean = false;
      
      // Check that the following character is not a space.
      pos2++;
      character = unicode_string_substr (usfm, pos2, 1);
      if (character != " ") isClean = false;
      
      // Fix the note caller if necessary.
      if (!isClean) {
        Database_Logs::log ("Fixing note caller in " + usfm);
        pos2--;
        usfm = unicode_string_substr (usfm, 0, pos2) + "+" + unicode_string_substr (usfm, pos2);
      }
      
      // Next iteration.
      pos = unicode_string_strpos (usfm, opener, pos + 5);
    }
  }
  
  return usfm;
}
Ejemplo n.º 26
0
// This function takes the html from an editor that edits one verse,
// and converts it to USFM.
// It properly deals with cases when a verse does not start a new paragraph.
string editor_export_verse (string stylesheet, string html)
{
  // When the $html starts with a paragraph without a style,
  // put a recognizable style there.
  string style = "oneversestyle";
  size_t pos = html.find ("<p>");
  if (pos == 0) {
    html.insert (2, " class=\"" + style + "\"");
  }

  // Convert html to USFM.
  Editor_Html2Usfm editor_export;
  editor_export.load (html);
  editor_export.stylesheet (stylesheet);
  editor_export.run ();
  string usfm = editor_export.get ();

  // Remove that recognizable style converted to USFM.
  usfm = filter_string_str_replace ("\\" + style, "", usfm);
  usfm = filter_string_trim (usfm);
  
  return usfm;
}
Ejemplo n.º 27
0
// handleEmailNew - handles an email received from $from with subject $subject and body $body.
// Returns true if the mail was processed, else false.
// The email is considered to have been processed if it created a new Consultation Note.
bool Notes_Logic::handleEmailNew (string from, string subject, string body)
{
  // Webserver request.
  Webserver_Request * request = (Webserver_Request *) webserver_request;
  // Store the original subject.
  string originalSubject = subject;
  // Check that the subject indicates that a new consultation note is to be created.
  size_t pos = unicode_string_casefold (subject).find ("new note");
  if (pos == string::npos) return false;
  // There is a new note. Remove that bit from the subject.
  if (pos > 0) subject.erase (0, pos + 8);
  // Clean the subject line.
  subject = filter_string_trim (subject);
  subject = filter_string_str_replace (".", " ", subject);
  subject = filter_string_str_replace (":", " ", subject);
  subject = filter_string_str_replace ("   ", " ", subject);
  subject = filter_string_str_replace ("  ", " ", subject);
  // Check that the from address of the email belongs to an existing user.
  from = filter_string_extract_email (from);
  if (!request->database_users()->emailExists (from)) return false;
  string username = request->database_users()->getEmailToUser (from);
  // Extract book, chapter, verse, and note summary from the subject
  int book = -1;
  int chapter = -1;
  int verse = -1;
  string summary;
  vector <string> subjectlines = filter_string_explode (subject, ' ');
  if (!subjectlines.empty()) {
    book = filter_passage_interpret_book (subjectlines[0]);
    subjectlines.erase (subjectlines.begin());
  }
  if (!subjectlines.empty()) {
    chapter = convert_to_int (subjectlines[0]);
    subjectlines.erase (subjectlines.begin());
  }
  if (!subjectlines.empty()) {
    verse = convert_to_int (subjectlines[0]);
    subjectlines.erase (subjectlines.begin());
  }
  summary = filter_string_implode (subjectlines, " ");
  // Check book, chapter, verse, and summary. Give feedback if there's anything wrong.
  string noteCheck;
  if (book <= 0) noteCheck.append (translate("Unknown book"));
  if (chapter < 0) {
    noteCheck.append (" ");
    noteCheck.append (translate("Unknown chapter"));
  }
  if (verse < 0) {
    noteCheck.append (" ");
    noteCheck.append (translate("Unknown verse"));
  }
  if (summary.empty ()) {
    noteCheck.append (" ");
    noteCheck.append (translate("Unknown summary"));
  }
  // Mail user if the note could not be posted.
  Database_Mail database_mail = Database_Mail (webserver_request);
  if (noteCheck != "") {
    subject = translate("Your new note could not be posted");
    database_mail.send (username, subject  + ": " + originalSubject, noteCheck);
    return false;
  }
  // Clean the email's body.
  body = filter_string_extract_body (body);
  // Post the note.
  string sessionuser = request->session_logic()->currentUser ();
  request->session_logic()->setUsername (username);
  Database_Notes database_notes = Database_Notes(webserver_request);
  string bible = request->database_config_user()->getBible ();
  int identifier = database_notes.storeNewNote (bible, book, chapter, verse, summary, body, false);
  handlerNewNote (identifier);
  request->session_logic()->setUsername (sessionuser);
  // Mail confirmation to the username.
  if (request->database_config_user()->getUserNotifyMeOfMyPosts (username)) {
    subject = translate("Your new note was posted");
    database_mail.send (username, subject + ": " + originalSubject, body);
  }
  // Log operation.
  Database_Logs::log ("New note posted : " + body);
  // Job done.
  return true;
}
Ejemplo n.º 28
0
string sync_changes (void * webserver_request)
{
  Webserver_Request * request = (Webserver_Request *) webserver_request;
  Sync_Logic sync_logic = Sync_Logic (webserver_request);
  Database_Modifications database_modifications;

  // Check on the credentials.
  if (!sync_logic.credentials_okay ()) return "";

  // Bail out if the change notifications are not now available to clients.
  if (!config_globals_change_notifications_available) {
    request->response_code = 503;
    return "";
  }
  
  // Client makes a prioritized server call: Record the client's IP address.
  sync_logic.prioritized_ip_address_record ();

  // Get the relevant parameters the client may have POSTed to us, the server.
  string user = hex2bin (request->post ["u"]);
  int action = convert_to_int (request->post ["a"]);
  int id = convert_to_int (request->post ["i"]);

  switch (action) {
    case Sync_Logic::changes_delete_modification:
    {
      // The server deletes the change notification.
      database_modifications.deleteNotification (id);
      Database_Logs::log ("Client deletes change notification from server: " + convert_to_string (id), Filter_Roles::translator ());
      request->database_config_user ()->setChangeNotificationsChecksum ("");
      return "";
    }
    case Sync_Logic::changes_get_checksum:
    {
      // The server responds with the possibly cached total checksum for the user's change notifications.
      string checksum = request->database_config_user ()->getChangeNotificationsChecksum ();
      if (checksum.empty ()) {
        checksum = Sync_Logic::changes_checksum (user);
        request->database_config_user ()->setChangeNotificationsChecksum (checksum);
      }
      return checksum;
    }
    case Sync_Logic::changes_get_identifiers:
    {
      // The server responds with the identifiers of all the user's change notifications.
      vector <int> ids = database_modifications.getNotificationIdentifiers (user, false);
      string response;
      for (auto & id : ids) {
        if (!response.empty ()) response.append ("\n");
        response.append (convert_to_string (id));
      }
      return response;
    }
    case Sync_Logic::changes_get_modification:
    {
      // The server responds with the relevant data of the requested modification.
      vector <string> lines;
      // category
      lines.push_back (database_modifications.getNotificationCategory (id));
      // bible
      lines.push_back (database_modifications.getNotificationBible (id));
      // book
      // chapter
      // verse
      Passage passage = database_modifications.getNotificationPassage (id);
      lines.push_back (convert_to_string (passage.book));
      lines.push_back (convert_to_string (passage.chapter));
      lines.push_back (passage.verse);
      // oldtext (ensure it's one line for correct transfer to client)
      string oldtext = database_modifications.getNotificationOldText (id);
      oldtext = filter_string_str_replace ("\n", " ", oldtext);
      lines.push_back (oldtext);
      // modification (ensure it's one line for correct transfer to client)
      string modification = database_modifications.getNotificationModification (id);
      modification = filter_string_str_replace ("\n", " ", modification);
      lines.push_back (modification);
      // newtext (ensure it's one line for correct transfer to client)
      string newtext = database_modifications.getNotificationNewText (id);
      newtext = filter_string_str_replace ("\n", " ", newtext);
      lines.push_back (newtext);
      // Result.
      return filter_string_implode (lines, "\n");
    }
  }

  
  // Bad request.
  // Delay a while to obstruct a flood of bad requests.
  this_thread::sleep_for (chrono::seconds (1));
  request->response_code = 400;
  return "";
}
Ejemplo n.º 29
0
string search_replacepre2 (void * webserver_request)
{
  Webserver_Request * request = (Webserver_Request *) webserver_request;
  
  
  string siteUrl = Database_Config_General::getSiteURL ();
  
  
  // Get search variables from the query.
  string searchfor = request->query ["q"];
  string replacewith = request->query ["r"];
  bool casesensitive = (request->query ["c"] == "true");
  string id = request->query ["id"];
  bool searchplain = (request->query ["p"] == "true");
  
  
  // Get the Bible and passage for this identifier.
  Passage details = Passage::from_text (id);
  string bible = details.bible;
  int book = details.book;
  int chapter = details.chapter;
  string verse = details.verse;
  
  
  // Get the plain text or the USFM.
  string text;
  if (searchplain) {
    text = search_logic_get_bible_verse_text (bible, book, chapter, convert_to_int (verse));
  } else {
    text = search_logic_get_bible_verse_usfm (bible, book, chapter, convert_to_int (verse));
  }
  
  // Clickable passage.
  string link = filter_passage_link_for_opening_editor_at (book, chapter, verse);
  
  
  string oldtext = filter_string_markup_words ({searchfor}, text);
  

  string newtext (text);
  if (casesensitive) {
    newtext = filter_string_str_replace (searchfor, replacewith, newtext);
  } else {
    vector <string> needles = filter_string_search_needles (searchfor, text);
    for (auto & needle : needles) {
      newtext = filter_string_str_replace (needle, replacewith, newtext);
    }
  }
  if (replacewith != "") newtext = filter_string_markup_words ({replacewith}, newtext);
  
  
  // The id sent to the browser contains bible identifier, book, chapter, and verse.
  int bibleID = request->database_bibles()->getID (bible);
  vector <string> bits = {convert_to_string (bibleID), convert_to_string (book), convert_to_string (chapter), verse};
  string s_id = filter_string_implode (bits, "_");
  
  
  // Check whether the user has write access to the book.
  string user = request->session_logic ()->currentUser ();
  bool write = access_bible_book_write (webserver_request, user, bible, book);

  
  // Create output.
  string output;
  output.append ("<div id=\"" + s_id + "\">\n");
  output.append ("<p>");
  if (write) output.append ("<a href=\"replace\"> ✔ </a> <a href=\"delete\"> ✗ </a> ");
  output.append (link);
  output.append ("</p>\n");
  output.append ("<p>" + oldtext + "</p>\n");
  output.append ("<p>");
  if (write) output.append (newtext);
  else output.append (locale_logic_text_no_privileges_modify_book ());
  output.append ("</p>\n");
  output.append ("</div>\n");
  
  
  // Output to browser.
  return output;
}
Ejemplo n.º 30
0
// This is the most basic version that fetches the text of a $resource.
// It works on server and on client.
// It uses the cache.
string resource_logic_get_verse (void * webserver_request, string resource, int book, int chapter, int verse)
{
  Webserver_Request * request = (Webserver_Request *) webserver_request;

  string data;

  Database_UsfmResources database_usfmresources;
  Database_ImageResources database_imageresources;
  
  // Lists of the various types of resources.
  // As from February 2016 a client no longer automatically downloads USFM resources from the Cloud.
  // But a client takes in account existing USFM resources it has downloaded before.
  vector <string> bibles = request->database_bibles()->getBibles ();
  vector <string> local_usfms = database_usfmresources.getResources ();
  vector <string> remote_usfms;
  if (config_logic_client_prepared ()) {
    remote_usfms = client_logic_usfm_resources_get ();
  }
  vector <string> externals = resource_external_names ();
  vector <string> images = database_imageresources.names ();
  vector <string> lexicons = lexicon_logic_resource_names ();
  
  // Possible SWORD details.
  string sword_module = sword_logic_get_remote_module (resource);
  string sword_source = sword_logic_get_source (resource);
  
  // Determine the type of the current resource.
  bool isBible = in_array (resource, bibles);
  bool isLocalUsfm = in_array (resource, local_usfms);
  bool isRemoteUsfm = in_array (resource, remote_usfms);
  bool isExternal = in_array (resource, externals);
  bool isImage = in_array (resource, images);
  bool isLexicon = in_array (resource, lexicons);
  bool isSword = (!sword_source.empty () && !sword_module.empty ());
  
  if (isBible || isLocalUsfm) {
    string chapter_usfm;
    if (isBible) chapter_usfm = request->database_bibles()->getChapter (resource, book, chapter);
    if (isLocalUsfm) chapter_usfm = database_usfmresources.getUsfm (resource, book, chapter);
    string verse_usfm = usfm_get_verse_text (chapter_usfm, verse);
    string stylesheet = styles_logic_standard_sheet ();
    Filter_Text filter_text = Filter_Text (resource);
    filter_text.html_text_standard = new Html_Text ("");
    filter_text.addUsfmCode (verse_usfm);
    filter_text.run (stylesheet);
    data = filter_text.html_text_standard->getInnerHtml ();
  } else if (isRemoteUsfm) {
    data = resource_logic_client_fetch_cache_from_cloud (resource, book, chapter, verse);
  } else if (isExternal) {
    if (config_logic_client_prepared ()) {
      // A client fetches it from the cache or from the Cloud,
      // or, for older versions, from the offline resources database.
      // As of 12 December 2015, the offline resources database is not needed anymore.
      // It can be removed after a year or so.
      Database_OfflineResources database_offlineresources;
      if (database_offlineresources.exists (resource, book, chapter, verse)) {
        data = database_offlineresources.get (resource, book, chapter, verse);
      } else {
        data = resource_logic_client_fetch_cache_from_cloud (resource, book, chapter, verse);
      }
    } else {
      // The server fetches it from the web, via the http cache.
      data.append (resource_external_cloud_fetch_cache_extract (resource, book, chapter, verse));
    }
    
  } else if (isImage) {
    vector <string> images = database_imageresources.get (resource, book, chapter, verse);
    for (auto & image : images) {
      data.append ("<div><img src=\"/resource/imagefetch?name=" + resource + "&image=" + image + "\" alt=\"Image resource\" style=\"width:100%\"></div>");
    }
  } else if (isLexicon) {
    data = lexicon_logic_get_html (request, resource, book, chapter, verse);
  } else if (isSword) {
    data = sword_logic_get_text (sword_source, sword_module, book, chapter, verse);
  } else {
    // Nothing found.
  }
  
  // Any font size given in a paragraph style may interfere with the font size setting for the resources
  // as given in Bibledit. For that reason remove the class name from a paragraph style.
  for (unsigned int i = 0; i < 5; i++) {
    string fragment = "p class=\"";
    size_t pos = data.find (fragment);
    if (pos != string::npos) {
      size_t pos2 = data.find ("\"", pos + fragment.length () + 1);
      if (pos2 != string::npos) {
        data.erase (pos + 1, pos2 - pos + 1);
      }
    }
  }
  
  // NET Bible updates.
  data = filter_string_str_replace ("<span class=\"s ", "<span class=\"", data);

  return data;
}