public boolean logEvent(
      final IClient client, final String eventText, final InputStream logFileStream) {
    Integer id =
        executeWithConnection(
            new ConnectionExecuteFunction<Integer>() {
              public Integer execute(Connection c) throws SQLException {
                return logEvent(client, eventText, logFileStream, c);
              }
            });

    if (id == null) {
      // DB error would have already been logged.
      return false;
    }

    boolean ok = false;
    if (logFileStream == null) {
      ok = true;
    } else {
      File userMailDir = client.getUserMailbox().getBaseDir();
      File logFile = getEventLogFile(userMailDir, id.intValue());
      try {
        FileUtils.copyStreamToFile(logFileStream, logFile);
        ok = true;
      } catch (IOException ioe) {
        m_logger
            .log("Can't write log file")
            .param(LoggingConsts.USER_ID, client.getUserId())
            .param(LoggingConsts.FILENAME, logFile == null ? "" : logFile.getAbsolutePath())
            .param(LoggingConsts.CONTENT, eventText)
            .error(ioe);
      }
    }
    return ok;
  }
  /** Returns event_id of newly created logging entry. */
  private Integer logEvent(IClient client, String eventText, InputStream logFileSteam, Connection c)
      throws SQLException {
    PreparedStatement stmt = null;
    int id = 0;
    try {
      long longId = getSequenceId("seq_client_log_event_ids", c);
      if (longId > Integer.MAX_VALUE) {
        // dat_client_log_events.event_id is a 32 bit integer numeric type.

        // this is a bad problem; ensure it's logged; don't depend on whoever's catching
        // the exception.
        m_logger.log("seq_client_log_event_ids overflowed").error();
        throw new IllegalStateException("seq_client_log_event_ids overflowed.");
      }
      id = (int) longId;
      stmt =
          c.prepareStatement(
              "insert into dat_client_log_events "
                  + "(event_id, customer_id, user_id, event_time, description, has_log_file) "
                  + "values "
                  + "(?, ?, ?, current_timestamp, ?, ?)");

      stmt.setInt(1, id);
      stmt.setInt(2, client.getCustomerId());
      stmt.setInt(3, client.getUserId());
      stmt.setString(4, eventText);
      stmt.setInt(5, logFileSteam == null ? 0 : 1);
      if (stmt.executeUpdate() != 1) {
        throw new SQLException("Can't insert client event for " + client);
      }
    } finally {
      DbUtils.safeClose(stmt);
    }
    return new Integer(id);
  }
  /**
   * Update the mail signal file with a current timestamp.
   *
   * @param client
   */
  public void stampNewmailFile(IClient client) {
    if (client == null) {
      return;
    }
    String cachePath = client.getNewMailCachePath();
    File f = new File(getCacheBase(), cachePath);

    // matches scheme used in smtpnotify.py
    long stamp = System.currentTimeMillis() / 5000;
    byte[] content = Long.toString(stamp).getBytes();

    // It's not necessary to write the file atomically.
    // It's not critical information; the worst that can happen is
    // the client does an unnecessary retrieve call into the backend.
    touchFile(f, content, client.getUserId(), false);
  }