Ejemplo n.º 1
0
static struct folder_ref_info *
storage_folder_add_ref(struct storage_ref_info * ref_info,
                       struct mailfolder * folder)
{
    struct folder_ref_info * folder_ref;
    chashdatum key;
    chashdatum value;
    int r;

    folder_ref = folder_ref_info_new(folder /*, ref_info->msg_folder_finder */);
    if (folder_ref == NULL)
        goto err;

    key.data = &folder;
    key.len = sizeof(folder);
    value.data = folder_ref;
    value.len = 0;
    r = chash_set(ref_info->folder_ref_info, &key, &value, NULL);
    if (r < 0)
        goto free;

    return folder_ref;

free:
    folder_ref_info_free(folder_ref);
err:
    return NULL;
}
Ejemplo n.º 2
0
int nntp_threaded_connect(Folder * folder, const char * server, int port)
{
	struct connect_param param;
	struct connect_result result;
	chashdatum key;
	chashdatum value;
	newsnntp * nntp, * oldnntp;
	
	oldnntp = get_nntp(folder);

	nntp = newsnntp_new(0, NULL);
	
	if (oldnntp) {
		debug_print("deleting old nntp %p\n", oldnntp);
		delete_nntp(folder, oldnntp);
	}
	
	key.data = &folder;
	key.len = sizeof(folder);
	value.data = nntp;
	value.len = 0;
	chash_set(session_hash, &key, &value, NULL);
	
	param.nntp = nntp;
	param.server = server;
	param.port = port;
	
	refresh_resolvers();
	threaded_run(folder, &param, &result, connect_run);
	
	debug_print("connect ok %i with nntp %p\n", result.error, nntp);
	
	return result.error;
}
Ejemplo n.º 3
0
int mailprivacy_smime_set_encryption_id(struct mailprivacy * privacy,
    char * user_id, char * passphrase)
{
  chashdatum key;
  chashdatum value;
  int r;
  char buf[MAX_EMAIL_SIZE];
  char * n;
  
  strncpy(buf, user_id, sizeof(buf));
  buf[sizeof(buf) - 1] = '\0';
  for(n = buf ; * n != '\0' ; n ++)
    * n = toupper((unsigned char) * n);
  
  if (passphrase_hash == NULL) {
    passphrase_hash = chash_new(CHASH_DEFAULTSIZE, CHASH_COPYALL);
    if (passphrase_hash == NULL)
      return MAIL_ERROR_MEMORY;
  }
  
  key.data = buf;
  key.len = strlen(buf) + 1;
  value.data = passphrase;
  value.len = strlen(passphrase) + 1;
  
  r = chash_set(passphrase_hash, &key, &value, NULL);
  if (r < 0) {
    return MAIL_ERROR_MEMORY;
  }
  
  return MAIL_NO_ERROR;
}
Ejemplo n.º 4
0
int mail_cache_db_get_keys(struct mail_cache_db * cache_db,
    chash * keys)
{
  DB * dbp;
  int r;
  DBT db_key;
  DBT db_data;
  
  dbp = cache_db->internal_database;
  
  r = dbp->seq(dbp, &db_key, &db_data, R_FIRST);
  if (r == -1)
    return -1;
  
  while (r == 0) {
    chashdatum hash_key;
    chashdatum hash_data;
    
    hash_key.data = db_key.data;
    hash_key.len = db_key.size;
    hash_data.data = NULL;
    hash_data.len = 0;
    
    r = chash_set(keys, &hash_key, &hash_data, NULL);
    if (r < 0) {
      return -1;
    }
    
    r = dbp->seq(dbp, &db_key, &db_data, R_NEXT);
    if (r < 0)
      return -1;
  }
  
  return 0;
}
Ejemplo n.º 5
0
int mmap_string_ref(MMAPString * string)
{
  chash * ht;
  int r;
  chashdatum key;
  chashdatum data;
  
  pthread_mutex_lock(&mmapstring_lock);
  if (mmapstring_hashtable == NULL) {
    mmapstring_hashtable_init();
  }
  ht = mmapstring_hashtable;
  
  if (ht == NULL) {
    pthread_mutex_unlock(&mmapstring_lock);
    return -1;
  }
  
  key.data = &string->str;
  key.len = sizeof(string->str);
  data.data = string;
  data.len = 0;
  
  r = chash_set(mmapstring_hashtable, &key, &data, NULL);
  pthread_mutex_unlock(&mmapstring_lock);
  
  if (r < 0)
    return r;

  return 0;
}
Ejemplo n.º 6
0
static int folder_message_add(struct folder_ref_info * ref_info,
                              mailmessage * msg)
{
    chashdatum key;
    chashdatum data;
    struct message_ref_elt * msg_ref;
    int r;

    msg_ref = message_ref_elt_new(ref_info->folder, msg);
    if (msg_ref == NULL)
        goto err;

    key.data = &msg;
    key.len = sizeof(msg);
    data.data = msg_ref;
    data.len = 0;

    r = chash_set(ref_info->msg_hash, &key, &data, NULL);
    if (r < 0)
        goto free_msg_ref;

    if (msg->msg_uid != NULL) {
        key.data = msg->msg_uid;
        key.len = strlen(msg->msg_uid);
        data.data = msg;
        data.len = 0;

        r = chash_set(ref_info->uid_hash, &key, &data, NULL);
        if (r < 0)
            goto remove_msg_ref;
    }

    return MAIL_NO_ERROR;

remove_msg_ref:
    key.data = &msg;
    key.len = sizeof(msg);
    chash_delete(ref_info->msg_hash, &key, NULL);
free_msg_ref:
    message_ref_elt_free(msg_ref);
err:
    return MAIL_ERROR_MEMORY;
}
Ejemplo n.º 7
0
static int mailprivacy_smime_add_encryption_id(struct mailprivacy * privacy,
    mailmessage * msg, char * encryption_id)
{
  clist * encryption_id_list;
  int r;
  int res;
  
  LOCK();
  
  res = -1;
  
  encryption_id_list = get_list(privacy, msg);
  if (encryption_id_list == NULL) {
    if (encryption_id_hash == NULL)
      encryption_id_hash = chash_new(CHASH_DEFAULTSIZE, CHASH_COPYKEY);
    
    if (encryption_id_hash != NULL) {
      encryption_id_list = clist_new();
      if (encryption_id_list != NULL) {
        chashdatum key;
        chashdatum value;
        
        key.data = &msg;
        key.len = sizeof(msg);
        value.data = encryption_id_list;
        value.len = 0;
        r = chash_set(encryption_id_hash, &key, &value, NULL);
        if (r < 0)
          clist_free(encryption_id_list);
      }
    }
  }
  
  encryption_id_list = get_list(privacy, msg);
  if (encryption_id_list != NULL) {
    char * str;
    
    str = strdup(encryption_id);
    if (str != NULL) {
      r = clist_append(encryption_id_list, str);
      if (r < 0) {
        free(str);
      }
      else {
        res = 0;
      }
    }
  }
  
  UNLOCK();
  
  return res;
}
Ejemplo n.º 8
0
int mailmh_folder_add_subfolder(struct mailmh_folder * parent,
				const char * name)
{
  char * foldername;
  int r;
  struct mailmh_folder * folder;
  unsigned int array_index;
  chashdatum key;
  chashdatum data;

  foldername = malloc(strlen(parent->fl_filename) + strlen(name) + 2);
  if (foldername == NULL)
    return MAILMH_ERROR_MEMORY;
  strcpy(foldername, parent->fl_filename);
  strcat(foldername, MAIL_DIR_SEPARATOR_S);
  strcat(foldername, name);

#ifdef WIN32
  r = mkdir(foldername);
#else
  r = mkdir(foldername, 0700);
#endif
  free(foldername);

  if (r < 0)
    return MAILMH_ERROR_FOLDER;

  folder = mailmh_folder_new(parent, name);
  if (folder == NULL)
    return MAILMH_ERROR_MEMORY;
  
  r = carray_add(parent->fl_subfolders_tab, folder, &array_index);
  if (r < 0) {
    mailmh_folder_free(folder);
    return MAILMH_ERROR_MEMORY;
  }
  folder->fl_array_index = array_index;

  key.data = folder->fl_filename;
  key.len = strlen(folder->fl_filename);
  data.data = folder;
  data.len = 0;

  r = chash_set(parent->fl_subfolders_hash, &key, &data, NULL);
  if (r < 0) {
    carray_delete_fast(folder->fl_subfolders_tab, folder->fl_array_index);
    mailmh_folder_free(folder);
    return MAILMH_ERROR_MEMORY;
  }

  return MAILMH_NO_ERROR;
}
Ejemplo n.º 9
0
int mail_cache_db_get_keys(struct mail_cache_db * cache_db,
    chash * keys)
{
  int r;
  MDB_env *env;
  MDB_txn *txn;
  MDB_dbi dbi;
  MDB_cursor *cursor;
  MDB_val mdb_key;
  MDB_val mdb_val;

  env = cache_db->internal_database;

  r = mdb_txn_begin(env, NULL, 0, &txn);
  if (r != 0)
    return -1;
  r = mdb_dbi_open(txn, NULL, 0, &dbi);
  if (r != 0)
    goto error;

  r = mdb_cursor_open(txn, dbi, &cursor);
  if (r != 0)
    goto error;

  r = mdb_cursor_get(cursor, &mdb_key, &mdb_val, MDB_FIRST);
  if (r != 0)
    goto cursor_error;

  while (r == 0) {
    chashdatum hash_key;
    chashdatum hash_data;

    hash_key.data = mdb_key.mv_data;
    hash_key.len = (unsigned int) mdb_key.mv_size;
    hash_data.data = NULL;
    hash_data.len = 0;

    r = chash_set(keys, &hash_key, &hash_data, NULL);
    if (r != 0)
      goto cursor_error;
    r = mdb_cursor_get(cursor, &mdb_key, &mdb_val, MDB_NEXT);
  }

  mdb_txn_commit(txn);
  return 0;

  cursor_error:
    mdb_cursor_close(cursor);
  error:
    mdb_txn_abort(txn);
  return -1;
}
Ejemplo n.º 10
0
void nntp_init(Folder * folder)
{
	struct etpan_thread * thread;
	chashdatum key;
	chashdatum value;
	
	thread = etpan_thread_manager_get_thread(thread_manager);
	
	key.data = &folder;
	key.len = sizeof(folder);
	value.data = thread;
	value.len = 0;
	
	chash_set(nntp_hash, &key, &value, NULL);
}
Ejemplo n.º 11
0
static int register_mime(struct mailprivacy * privacy,
    struct mailmime * mime)
{
  chashdatum key;
  chashdatum data;
  int r;
  
  key.data = &mime;
  key.len = sizeof(mime);
  data.data = mime;
  data.len = 0;
  
  r = chash_set(privacy->mime_ref, &key, &data, NULL);
  if (r < 0)
    return MAIL_ERROR_MEMORY;
  else
    return MAIL_NO_ERROR;
}
Ejemplo n.º 12
0
static int register_result_mmapstr(struct mailprivacy * privacy,
    char * content)
{
  chashdatum key;
  chashdatum data;
  int r;
  
  key.data = &content;
  key.len = sizeof(content);
  data.data = content;
  data.len = 0;
  
  r = chash_set(privacy->mmapstr, &key, &data, NULL);
  if (r < 0)
    return MAIL_ERROR_MEMORY;
  
  return 0;
}
Ejemplo n.º 13
0
int nntp_threaded_connect_ssl(Folder * folder, const char * server, int port)
{
	struct connect_param param;
	struct connect_result result;
	chashdatum key;
	chashdatum value;
	newsnntp * nntp, * oldnntp;
	gboolean accept_if_valid = FALSE;

	oldnntp = get_nntp(folder);

	nntp = newsnntp_new(0, NULL);

	if (oldnntp) {
		debug_print("deleting old nntp %p\n", oldnntp);
		delete_nntp(folder, oldnntp);
	}

	key.data = &folder;
	key.len = sizeof(folder);
	value.data = nntp;
	value.len = 0;
	chash_set(session_hash, &key, &value, NULL);

	param.nntp = nntp;
	param.server = server;
	param.port = port;
	param.account = folder->account;

	if (folder->account)
		accept_if_valid = folder->account->ssl_certs_auto_accept;

	refresh_resolvers();
	threaded_run(folder, &param, &result, connect_ssl_run);

	if (result.error == NEWSNNTP_NO_ERROR && !etpan_skip_ssl_cert_check) {
		if (etpan_certificate_check(nntp->nntp_stream, server, port,
					    accept_if_valid) != TRUE)
			return -1;
	}
	debug_print("connect %d with nntp %p\n", result.error, nntp);
	
	return result.error;
}
Ejemplo n.º 14
0
int nntp_threaded_connect_ssl(Folder * folder, const char * server, int port)
{
	struct connect_param param;
	struct connect_result result;
	chashdatum key;
	chashdatum value;
	newsnntp * nntp, * oldnntp;
	unsigned char *certificate = NULL;
	int cert_len;
	
	oldnntp = get_nntp(folder);

	nntp = newsnntp_new(0, NULL);
	
	if (oldnntp) {
		debug_print("deleting old nntp %p\n", oldnntp);
		delete_nntp(folder, oldnntp);
	}

	key.data = &folder;
	key.len = sizeof(folder);
	value.data = nntp;
	value.len = 0;
	chash_set(session_hash, &key, &value, NULL);
	
	param.nntp = nntp;
	param.server = server;
	param.port = port;
	param.account = folder->account;

	refresh_resolvers();
	threaded_run(folder, &param, &result, connect_ssl_run);

	if (result.error == NEWSNNTP_NO_ERROR && !etpan_skip_ssl_cert_check) {
		cert_len = (int)mailstream_ssl_get_certificate(nntp->nntp_stream, &certificate);
		if (etpan_certificate_check(certificate, cert_len, &param) < 0)
			return -1;
		if (certificate) 
			free(certificate); 
	}
	debug_print("connect %d with nntp %p\n", result.error, nntp);
	
	return result.error;
}
Ejemplo n.º 15
0
int mail_cache_db_get_keys(struct mail_cache_db * cache_db,
    chash * keys)
{
  DB * dbp;
  int r;
  DBC * dbcp;
  DBT db_key;
  DBT db_data;
  
  dbp = cache_db->internal_database;
  
  r = dbp->cursor(dbp, NULL, &dbcp, 0);
  if (r != 0)
    return -1;
  
  memset(&db_key, 0, sizeof(db_key));
  memset(&db_data, 0, sizeof(db_data));
  
  while (1) {
    chashdatum hash_key;
    chashdatum hash_data;
    
    r = dbcp->c_get(dbcp, &db_key, &db_data, DB_NEXT);
    if (r != 0)
      break;
    
    hash_key.data = db_key.data;
    hash_key.len = db_key.size;
    hash_data.data = NULL;
    hash_data.len = 0;
    
    r = chash_set(keys, &hash_key, &hash_data, NULL);
    if (r < 0) {
      return -1;
    }
  }
  
  r = dbcp->c_close(dbcp);
  if (r != 0)
    return -1;
  
  return 0;
}
Ejemplo n.º 16
0
static void set_file(chash * hash, char * email, char * filename)
{
  char * n;
  char buf[MAX_EMAIL_SIZE];
  chashdatum key;
  chashdatum data;

  strncpy(buf, email, sizeof(buf));
  buf[sizeof(buf) - 1] = '\0';
  for(n = buf ; * n != '\0' ; n ++)
    * n = toupper((unsigned char) * n);
  strip_string(buf);
  
  key.data = buf;
  key.len = strlen(buf);
  data.data = filename;
  data.len = strlen(filename) + 1;
  
  chash_set(hash, &key, &data, NULL);
}
Ejemplo n.º 17
0
static int register_msg(struct mailprivacy * privacy,
    mailmessage * msg)
{
  chashdatum key;
  chashdatum data;
  int r;
  
  if (privacy == NULL)
    return MAIL_NO_ERROR;
  
  key.data = &msg;
  key.len = sizeof(msg);
  data.data = msg;
  data.len = 0;
  
  r = chash_set(privacy->msg_ref, &key, &data, NULL);
  if (r < 0)
    return MAIL_ERROR_MEMORY;
  else
    return MAIL_NO_ERROR;
}
Ejemplo n.º 18
0
static struct storage_ref_info *
add_storage_ref_info(struct mailengine * engine,
                     struct mailstorage * storage)
{
    chashdatum key;
    chashdatum data;
    int r;
    struct storage_ref_info * ref_info;

    ref_info = storage_ref_info_new(storage
                                    /* , &engine->msg_folder_finder */);
    if (ref_info == NULL)
        goto err;

    key.data = &storage;
    key.len = sizeof(storage);
    data.data = ref_info;
    data.len = 0;

#ifdef LIBETPAN_REENTRANT
    pthread_mutex_lock(&engine->storage_hash_lock);
#endif
    r = chash_set(engine->storage_hash, &key, &data, NULL);
#ifdef LIBETPAN_REENTRANT
    pthread_mutex_unlock(&engine->storage_hash_lock);
#endif
    if (r < 0)
        goto free;

    ref_info = data.data;

    return ref_info;

free:
    storage_ref_info_free(ref_info);
err:
    return NULL;
}
Ejemplo n.º 19
0
Archivo: test.c Proyecto: Zolok/refos
static int
test_chash(void)
{
    test_start("chash");
    chash_t h;
    chash_init(&h, 12);
    for (int i = 0; i < 1024; i++) {
        chash_set(&h, i, (chash_item_t) 0x3F1);
    }
    for (int i = 0; i < 1024; i++) {
        int t = (int) chash_get(&h, i);
        test_assert(t == 0x3F1);
    }
    chash_remove(&h, 123);
    test_assert(chash_get(&h, 123) == NULL);
    int f = chash_find_free(&h, 100, 200);
    test_assert(f == 123);
    for (int i = 0; i < 1024; i++) {
        chash_remove(&h, i);
    }
    chash_release(&h);
    return test_success();
}
Ejemplo n.º 20
0
static int
mail_build_thread_references(char * default_from,
    struct mailmessage_list * env_list,
    struct mailmessage_tree ** result,
    int use_subject, 
    int (* comp_func)(struct mailmessage_tree **,
        struct mailmessage_tree **))
{
  int r;
  int res;
  chash * msg_id_hash;
  unsigned int cur;
  struct mailmessage_tree * root;
  carray * rootlist;
  carray * msg_list;
  unsigned int i;
  chash * subject_hash;

  msg_id_hash = chash_new(128, CHASH_COPYNONE);
  if (msg_id_hash == NULL) {
    res = MAIL_ERROR_MEMORY;
    goto err;
  }

  root = mailmessage_tree_new(NULL, (time_t) -1, NULL);
  if (root == NULL) {
    res = MAIL_ERROR_MEMORY;
    goto free_hash;
  }
  rootlist = root->node_children;

  msg_list = carray_new(128);
  if (msg_list == NULL) {
    res = MAIL_ERROR_MEMORY;
    goto free_root;
  }

  /* collect message-ID */
  for(i = 0 ; i < carray_count(env_list->msg_tab) ; i ++) {
    mailmessage * msg;
    char * msgid;
    struct mailmessage_tree * env_tree;
    chashdatum hashkey;
    chashdatum hashdata;
    chashdatum hashold;
    time_t date;

    msg = carray_get(env_list->msg_tab, i);

    if (msg == NULL)
      continue;

    if (msg->msg_fields != NULL) {
      msgid = get_msg_id(msg);

      if (msgid == NULL) {
	msgid = mailimf_get_message_id();
      }
      else {
	hashkey.data = msgid;
	hashkey.len = strlen(msgid);
	
	if (chash_get(msg_id_hash, &hashkey, &hashdata) == 0)
	  msgid = mailimf_get_message_id();
	else
	  msgid = strdup(msgid);
      }
      
      if (msgid == NULL) {
	res = MAIL_ERROR_MEMORY;
	goto free_list;
      }
      
      date = get_date(msg);
      
      env_tree = mailmessage_tree_new(msgid, date, msg);
      if (env_tree == NULL) {
	res = MAIL_ERROR_MEMORY;
	goto free_list;
      }
      
      r = carray_add(msg_list, env_tree, NULL);
      if (r < 0) {
	mailmessage_tree_free(env_tree);
	res = MAIL_ERROR_MEMORY;
	goto free_list;
      }
      
      hashkey.data = msgid;
      hashkey.len = strlen(msgid);
      
      hashdata.data = env_tree;
      hashdata.len = 0;
      
      r = chash_set(msg_id_hash, &hashkey, &hashdata, &hashold);
      if (r < 0) {
	res = MAIL_ERROR_MEMORY;
	goto free_list;
      }
    }
  }

  /* (1) for all messages */

  for(cur = 0 ; cur < carray_count(msg_list) ; cur ++) {
    struct mailmessage_tree * env_tree;
    mailmessage * msg;
    clist * ref;

    env_tree = carray_get(msg_list, cur);

    msg = env_tree->node_msg;

    ref = NULL;
    if (msg != NULL) {
      ref = get_ref(msg);
      if (ref == NULL)
	ref = get_in_reply_to(msg);
    }      

    /* (A) Using the Message IDs in the message's references, link
       the corresponding messages (those whose Message-ID header
       line contains the given reference Message ID) together as
       parent/child.
    */

    if (ref != NULL) {
      /* try to start a tree */

      clistiter * cur_ref;
      chashdatum hashkey;
      chashdatum hashdata;
      chashdatum hashold;
      struct mailmessage_tree * env_cur_tree;
      struct mailmessage_tree * last_env_cur_tree;

      env_cur_tree = NULL;
      for(cur_ref = clist_begin(ref) ; cur_ref != NULL ;
	  cur_ref = clist_next(cur_ref)) {
	char * msgid;

	last_env_cur_tree = env_cur_tree;

	msgid = clist_content(cur_ref);

	hashkey.data = msgid;
	hashkey.len = strlen(msgid);
	
	r = chash_get(msg_id_hash, &hashkey, &hashdata);
	if (r < 0) {
	  /* not found, create a dummy message */
	  msgid = strdup(msgid);
	  if (msgid == NULL) {
	    res = MAIL_ERROR_MEMORY;
	    goto free_list;
	  }

	  env_cur_tree = mailmessage_tree_new(msgid, (time_t) -1, NULL);
	  if (env_cur_tree == NULL) {
	    free(msgid);
	    res = MAIL_ERROR_MEMORY;
	    goto free_list;
	  }

	  r = carray_add(msg_list, env_cur_tree, NULL);
	  if (r < 0) {
	    mailmessage_tree_free(env_cur_tree);
	    res = MAIL_ERROR_MEMORY;
	    goto free_list;
	  }

	  hashkey.data = msgid;
	  hashkey.len = strlen(msgid);
	    
	  hashdata.data = env_cur_tree;
	  hashdata.len = 0;
	  
	  r = chash_set(msg_id_hash, &hashkey, &hashdata, &hashold);
	  if (r < 0) {
	    res = MAIL_ERROR_MEMORY;
	    goto free_list;
	  }
	}
	else {
	  env_cur_tree = hashdata.data;
	}

	if (last_env_cur_tree != NULL) {
	  if (env_cur_tree->node_parent == NULL) {
	    /* make it one child */
	    if (env_cur_tree != last_env_cur_tree) {
	      if (!is_descendant(env_cur_tree, last_env_cur_tree)) {
                /* set parent */
		env_cur_tree->node_parent = last_env_cur_tree;
		r = carray_add(last_env_cur_tree->node_children,
                    env_cur_tree, NULL);
		if (r < 0) {
		  res = MAIL_ERROR_MEMORY;
		  goto free_list;
		}
	      }
	    }
	  }
	}
      }

      /* (B) Create a parent/child link between the last reference
	 (or NIL if there are no references) and the current message.
	 If the current message already has a parent, it is probably
	 the result of a truncated References header line, so break
	 the current parent/child link before creating the new
	 correct one.
      */
      
      last_env_cur_tree = env_cur_tree;
      
      if (last_env_cur_tree != NULL) {
	if (env_tree->node_parent == NULL) {
	  if (last_env_cur_tree != env_tree) {
	    if (!is_descendant(env_tree, last_env_cur_tree)) {
              /* set parent */
	      env_tree->node_parent = last_env_cur_tree;
	      r = carray_add(last_env_cur_tree->node_children, env_tree, NULL);
	      if (r < 0) {
		res = MAIL_ERROR_MEMORY;
		goto free_list;
	      }
	    }
	  }
	}
      }
    }
  }

  chash_free(msg_id_hash);
  msg_id_hash = NULL;

  /* (2) Gather together all of the messages that have no parents
     and make them all children (siblings of one another) of a dummy
     parent (the "root").
  */

  for(cur = 0 ; cur < carray_count(msg_list) ; cur ++) {
    struct mailmessage_tree * env_tree;

    env_tree = carray_get(msg_list, cur);
    if (env_tree->node_parent == NULL) {
      r = carray_add(rootlist, env_tree, NULL);
      if (r < 0) {
	res = MAIL_ERROR_MEMORY;
	goto free_list;
      }
      /* set parent */
      env_tree->node_parent = root;
    }
  }

  carray_free(msg_list);
  msg_list = NULL;

  /* (3) Prune dummy messages from the thread tree.
   */

  cur = 0;
  while (cur < carray_count(rootlist)) {
    r = delete_dummy(rootlist, rootlist, cur, &cur);
    if (r != MAIL_NO_ERROR) {
      res = r;
      goto free_list;
    }
  }

  /* (4) Sort the messages under the root (top-level siblings only)
     by sent date.
  */

  r = mail_thread_sort(root, mailthread_tree_timecomp, FALSE);
  if (r != MAIL_NO_ERROR) {
    res = r;
    goto free_list;
  }

  if (use_subject) {

    /* (5) Gather together messages under the root that have the same
       extracted subject text.

       (A) Create a table for associating extracted subjects with
       messages.
    */

    subject_hash = chash_new(128, CHASH_COPYVALUE);
    if (subject_hash == NULL) {
      res = MAIL_ERROR_MEMORY;
      goto free_list;
    }

    /*
      (B) Populate the subject table with one message per
      extracted subject.  For each child of the root:
    */

    for(cur = 0 ; cur < carray_count(rootlist) ; cur ++) {
      struct mailmessage_tree * env_tree;
      chashdatum key;
      chashdatum data;
      char * base_subject;

      env_tree = carray_get(rootlist, cur);

      /*
	(i) Find the subject of this thread by extracting the
	base subject from the current message, or its first child
	if the current message is a dummy.
      */

      r = get_thread_subject(default_from, env_tree, &base_subject);

      /*
	(ii) If the extracted subject is empty, skip this
	message.
      */

      if (r == MAIL_ERROR_SUBJECT_NOT_FOUND) {
	/* no subject found */
	continue;
      }
      else if (r == MAIL_NO_ERROR) {
	if (* base_subject == '\0') {
	  /* subject empty */
	  free(base_subject);
	  continue;
	}
	else {
	  /* do nothing */
	}
      }
      else {
	res = r;
	goto free_subject_hash;
      }

      env_tree->node_base_subject = base_subject;

      /*
	(iii) Lookup the message associated with this extracted
	subject in the table.
      */

      key.data = base_subject;
      key.len = strlen(base_subject);

      r = chash_get(subject_hash, &key, &data);

      if (r < 0) {
	/*
	  (iv) If there is no message in the table with this
	  subject, add the current message and the extracted
	  subject to the subject table.
	*/

	data.data = &cur;
	data.len = sizeof(cur);

	r = chash_set(subject_hash, &key, &data, NULL);
	if (r < 0) {
	  res = MAIL_ERROR_MEMORY;
	  goto free_subject_hash;
	}
      }
      else {
	/*
	  Otherwise, replace the message in the table with the
	  current message if the message in the table is not a
	  dummy AND either of the following criteria are true:
	  The current message is a dummy, OR                  
	  The message in the table is a reply or forward (its
	  original subject contains a subj-refwd part and/or a
	  "(fwd)" subj-trailer) and the current message is not.
	*/
	struct mailmessage_tree * msg_in_table;
	unsigned int * iter_in_table;
	int replace;

	iter_in_table = data.data;
	msg_in_table = carray_get(rootlist, cur);

	replace = FALSE;
	/* message is dummy if info is NULL */
	if (msg_in_table->node_msg != NULL) {

	  if (env_tree->node_msg == NULL)
	    replace = TRUE;
	  else {
	    if (env_tree->node_is_reply && !env_tree->node_is_reply)
	      replace = TRUE;
	  }
	}
 
	if (replace) {
	  data.data = &cur;
	  data.len = sizeof(cur);
	
	  r = chash_set(subject_hash, &key, &data, NULL);
	  if (r < 0) {
	    res = MAIL_ERROR_MEMORY;
	    goto free_subject_hash;
	  }
	}
      }
    }

    /*
      (C) Merge threads with the same subject.  For each child of
      the root:
    */

    cur = 0;
    while (cur < carray_count(rootlist)) {
      struct mailmessage_tree * env_tree;
      chashdatum key;
      chashdatum data;
      struct mailmessage_tree * main_tree;
      unsigned int * main_cur;

      env_tree = carray_get(rootlist, cur);

      if (env_tree == NULL)
        goto next_msg;

      /*
	(i) Find the subject of this thread as in step 4.B.i
	above.
      */
    
      /* already done in tree->node_base_subject */
    
      /*
	(ii) If the extracted subject is empty, skip this
	message.
      */
    
      if (env_tree->node_base_subject == NULL)
	goto next_msg;

      if (* env_tree->node_base_subject == '\0')
	goto next_msg;

      /*
	(iii) Lookup the message associated with this extracted
	subject in the table.
      */

      key.data = env_tree->node_base_subject;
      key.len = strlen(env_tree->node_base_subject);

      r = chash_get(subject_hash, &key, &data);
      if (r < 0)
	goto next_msg;

      /*
	(iv) If the message in the table is the current message,
	skip this message. 
      */
    
      main_cur = data.data;
      if (* main_cur == cur)
	goto next_msg;

      /*
	Otherwise, merge the current message with the one in the
	table using the following rules:
      */

      main_tree = carray_get(rootlist, * main_cur);

      /*
	If both messages are dummies, append the current
	message's children to the children of the message in
	the table (the children of both messages become
	siblings), and then delete the current message.
      */

      if ((env_tree->node_msg == NULL) && (main_tree->node_msg == NULL)) {
        unsigned int old_size;

        old_size = carray_count(main_tree->node_children);

        r = carray_set_size(main_tree->node_children, old_size +
            carray_count(env_tree->node_children));
        if (r < 0) {
          res = MAIL_ERROR_MEMORY;
          goto free_subject_hash;
        }

        for(i = 0 ; i < carray_count(env_tree->node_children) ; i ++) {
          struct mailmessage_tree * child;

          child = carray_get(env_tree->node_children, i);
          carray_set(main_tree->node_children, old_size + i, child);
          /* set parent */
          child->node_parent = main_tree;
        }
        carray_set_size(env_tree->node_children, 0);
	/* this is the only case where children can be NULL,
	   this is before freeing it */
	mailmessage_tree_free(env_tree);
        carray_delete_fast(rootlist, cur);
      }

      /*
	If the message in the table is a dummy and the current
	message is not, make the current message a child of
	the message in the table (a sibling of it's children).
      */

      else if (main_tree->node_msg == NULL) {
	r = carray_add(main_tree->node_children, env_tree, NULL);
	if (r < 0) {
	  res = MAIL_ERROR_MEMORY;
	  goto free_subject_hash;
	}
        /* set parent */
        env_tree->node_parent = main_tree;

	carray_delete_fast(rootlist, cur);
      }

      /*
	If the current message is a reply or forward and the
	message in the table is not, make the current message
	a child of the message in the table (a sibling of it's
	children).
      */

      else if (env_tree->node_is_reply && !main_tree->node_is_reply) {
	r = carray_add(main_tree->node_children, env_tree, NULL);
	if (r < 0) {
	  res = MAIL_ERROR_MEMORY;
	  goto free_subject_hash;
	}
        /* set parent */
        env_tree->node_parent = main_tree;

	carray_delete_fast(rootlist, cur);
      }

      /*
	Otherwise, create a new dummy message and make both
	the current message and the message in the table
	children of the dummy.  Then replace the message in
	the table with the dummy message.
	Note: Subject comparisons are case-insensitive, as
	described under "Internationalization
	Considerations."
      */

      else {
	struct mailmessage_tree * new_main_tree;
	char * base_subject;
        unsigned int last;

	new_main_tree = mailmessage_tree_new(NULL, (time_t) -1, NULL);
	if (new_main_tree == NULL) {
	  res = MAIL_ERROR_MEMORY;
	  goto free_subject_hash;
	}

	/* main_tree->node_base_subject is never NULL */

	base_subject = strdup(main_tree->node_base_subject);
	if (base_subject == NULL) {
	  mailmessage_tree_free(new_main_tree);
	  res = MAIL_ERROR_MEMORY;
	  goto free_subject_hash;
	}

	new_main_tree->node_base_subject = base_subject;

	r = carray_add(rootlist, new_main_tree, &last);
	if (r < 0) {
	  mailmessage_tree_free(new_main_tree);
	  res = MAIL_ERROR_MEMORY;
	  goto free_subject_hash;
	}

	r = carray_add(new_main_tree->node_children, main_tree, NULL);
	if (r < 0) {
	  res = MAIL_ERROR_MEMORY;
	  goto free_subject_hash;
	}
        /* set parent */
        main_tree->node_parent = new_main_tree;

	carray_delete_fast(rootlist, * main_cur);

	r = carray_add(new_main_tree->node_children, env_tree, NULL);
	if (r < 0) {
	  res = MAIL_ERROR_MEMORY;
	  goto free_subject_hash;
	}
        /* set parent */
        env_tree->node_parent = new_main_tree;

	carray_delete_fast(rootlist, cur);

	data.data = &last;
	data.len = sizeof(last);
      
	r = chash_set(subject_hash, &key, &data, NULL);

	if (r < 0) {
	  res = MAIL_ERROR_MEMORY;
	  goto free_subject_hash;
	}
      }

      continue;

    next_msg:
      cur ++;
      continue;
    }
    
    i = 0;
    for(cur = 0 ; cur < carray_count(rootlist) ; cur ++) {
      struct mailmessage_tree * env_tree;

      env_tree = carray_get(rootlist, cur);
      if (env_tree == NULL)
        continue;
      
      carray_set(rootlist, i, env_tree);
      i ++;
    }
    carray_set_size(rootlist, i);
    
    chash_free(subject_hash);
  }

  /*
    (6) Traverse the messages under the root and sort each set of
    siblings by sent date.  Traverse the messages in such a way
    that the "youngest" set of siblings are sorted first, and the
    "oldest" set of siblings are sorted last (grandchildren are
    sorted before children, etc).

    In the case of an exact match on
    sent date or if either of the Date: headers used in a
    comparison can not be parsed, use the order in which the
    messages appear in the mailbox (that is, by sequence number) to
    determine the order.  In the case of a dummy message (which can
    only occur with top-level siblings), use its first child for
    sorting.
  */

#if 0
  if (comp_func != NULL) {
    r = mail_thread_sort(root, comp_func, TRUE);
    if (r != MAIL_NO_ERROR) {
      res = r;
      goto free_list;
    }
  }
#endif
  if (comp_func == NULL)
    comp_func = mailthread_tree_timecomp;
  
  r = mail_thread_sort(root, comp_func, TRUE);
  if (r != MAIL_NO_ERROR) {
    res = r;
    goto free_list;
  }
  
  * result = root;

  return MAIL_NO_ERROR;

 free_subject_hash:
  chash_free(subject_hash);
 free_list:
  if (msg_list != NULL) {
    for(i = 0 ; i < carray_count(msg_list) ; i ++)
      mailmessage_tree_free(carray_get(msg_list, i));
    carray_free(msg_list);
  }
 free_root:
  mailmessage_tree_free_recursive(root);
 free_hash:
  if (msg_id_hash != NULL)
    chash_free(msg_id_hash);
 err:
  return res;
}
Ejemplo n.º 21
0
int claws_mailmbox_msg_info_update(struct claws_mailmbox_folder * folder,
			     size_t msg_start, size_t msg_start_len,
			     size_t msg_headers, size_t msg_headers_len,
			     size_t msg_body, size_t msg_body_len,
			     size_t msg_size, size_t msg_padding,
			     uint32_t msg_uid)
{
  struct claws_mailmbox_msg_info * info;
  int res;
  chashdatum key;
  chashdatum data;
  int r;
  
  key.data = &msg_uid;
  key.len = sizeof(msg_uid);
  r = chash_get(folder->mb_hash, &key, &data);
  if (r < 0) {
    unsigned int index;

    info = claws_mailmbox_msg_info_new(msg_start, msg_start_len,
        msg_headers, msg_headers_len,
        msg_body, msg_body_len, msg_size, msg_padding, msg_uid);
    if (info == NULL) {
      res = MAILMBOX_ERROR_MEMORY;
      goto err;
    }

    r = carray_add(folder->mb_tab, info, &index);
    if (r < 0) {
      claws_mailmbox_msg_info_free(info);
      res = MAILMBOX_ERROR_MEMORY;
      goto err;
    }

    if (msg_uid != 0) {
      chashdatum key;
      chashdatum data;
      
      key.data = &msg_uid;
      key.len = sizeof(msg_uid);
      data.data = info;
      data.len = 0;
      
      r = chash_set(folder->mb_hash, &key, &data, NULL);
      if (r < 0) {
	claws_mailmbox_msg_info_free(info);
	carray_delete(folder->mb_tab, index);
	res = MAILMBOX_ERROR_MEMORY;
	goto err;
      }
    }
    
    info->msg_index = index;
  }
  else {
    info = data.data;
    
    info->msg_start = msg_start;
    info->msg_start_len = msg_start_len;
    info->msg_headers = msg_headers;
    info->msg_headers_len = msg_headers_len;
    info->msg_body = msg_body;
    info->msg_body_len = msg_body_len;
    info->msg_size = msg_size;
    info->msg_padding = msg_padding;
  }

  return MAILMBOX_NO_ERROR;

 err:
  return res;
}
Ejemplo n.º 22
0
static int expunge_folder(mailsession * session)
{
  int r;
  char key_value[PATH_MAX];
  struct mail_cache_db * maildb;
  carray * msglist;
  unsigned int i;
  struct db_session_state_data * data;
  int res;
  chash * msg_table;
  MMAPString * mmapstr;
  
  data = get_data(session);
  
  flags_store_process(session);
  
  r = mail_cache_db_open_lock(data->db_filename, &maildb);
  if (r < 0) {
    res = MAIL_ERROR_FILE;
    goto err;
  }
  
  r = db_get_message_list(maildb, &msglist);
  if (r != MAIL_NO_ERROR) {
    res = r;
    goto close_db;
  }
  
  msg_table = chash_new(CHASH_DEFAULTSIZE, CHASH_COPYKEY);
  if (msg_table == NULL) {
    res = MAIL_ERROR_MEMORY;
    goto free_msglist;
  }
  
  mmapstr = mmap_string_new("");
  if (mmapstr == NULL) {
    res = MAIL_ERROR_MEMORY;
    goto free_msgtable;
  }
  
  i = 0;
  while (i < carray_count(msglist)) {
    uint32_t num;
    uint32_t * msg;
    chashdatum key;
    chashdatum value;
    struct mail_flags * flags;
    int deleted;
    
    msg = carray_get(msglist, i);
    num = * msg;
    
    deleted = 0;
    snprintf(key_value, sizeof(key_value), "%lu-flags",
        (unsigned long) num);
    r = generic_cache_flags_read(maildb, mmapstr, key_value, &flags);
    if (r == MAIL_NO_ERROR) {
      if ((flags->fl_flags & MAIL_FLAG_DELETED) != 0)
        deleted = 1;
    }
    
    if (!deleted) {
      snprintf(key_value, sizeof(key_value), "%lu", (unsigned long) num);
      key.data = key_value;
      key.len = strlen(key_value);
      chash_set(msg_table, &key, &value, NULL);
      
      snprintf(key_value, sizeof(key_value), "%lu-envelope",
          (unsigned long) num);
      key.data = key_value;
      key.len = strlen(key_value);
      chash_set(msg_table, &key, &value, NULL);
      
      snprintf(key_value, sizeof(key_value), "%lu-flags",
          (unsigned long) num);
      key.data = key_value;
      key.len = strlen(key_value);
      chash_set(msg_table, &key, &value, NULL);
      
      i ++;
    }
    else {
      free(msg);
      carray_delete(msglist, i);
    }
  }
  
  mmap_string_free(mmapstr);
  
  r = mail_cache_db_clean_up(maildb, msg_table);
  
  chash_free(msg_table);
  
  r = db_set_message_list(maildb, msglist);
  
  for(i = 0 ; i < carray_count(msglist) ; i ++) {
    uint32_t * msg;
    
    msg = carray_get(msglist, i);
    free(msg);
  }
  carray_free(msglist);
  
  mail_cache_db_close_unlock(data->db_filename, maildb);
  
  return MAIL_NO_ERROR;

 free_msgtable:
  chash_free(msg_table);
 free_msglist:
  for(i = 0 ; i < carray_count(msglist) ; i ++) {
    uint32_t * msg;
    
    msg = carray_get(msglist, i);
    free(msg);
  }
 close_db:
  mail_cache_db_close_unlock(data->db_filename, maildb);
 err:
  return res;
}
Ejemplo n.º 23
0
int mail_flags_store_set(struct mail_flags_store * flags_store,
			 mailmessage * msg)
{
  chashdatum key;
  chashdatum value;
  unsigned int indx;
  int res;
  int r;
  mailmessage * new_msg;

  if (msg->msg_flags == NULL) {
    res = MAIL_NO_ERROR;
    goto err;
  }

  /* duplicate needed message info */
  new_msg = mailmessage_build(msg);
  if (new_msg == NULL) {
    res = MAIL_ERROR_MEMORY;
    goto err;
  }

  key.data = &new_msg->msg_index;
  key.len = sizeof(new_msg->msg_index);

  r = chash_get(flags_store->fls_hash, &key, &value);
  if (r == 0) {
    mailmessage * old_msg;

    indx = * (unsigned int *) value.data;
    old_msg = carray_get(flags_store->fls_tab, indx);
    mailmessage_free(old_msg);
  }
  else {
    r = carray_set_size(flags_store->fls_tab,
        carray_count(flags_store->fls_tab) + 1);
    if (r != 0) {
      res = MAIL_ERROR_MEMORY;
      goto err;
    }
    indx = carray_count(flags_store->fls_tab) - 1;
  }

  carray_set(flags_store->fls_tab, indx, new_msg);
  
  value.data = &indx;
  value.len = sizeof(indx);

  r = chash_set(flags_store->fls_hash, &key, &value, NULL);
  if (r < 0) {
    carray_delete(flags_store->fls_tab, indx);
    res = MAIL_ERROR_MEMORY;
    goto free;
  }

  return MAIL_NO_ERROR;

 free:
  mailmessage_free(new_msg);
 err:
  return res;
}
Ejemplo n.º 24
0
int maildriver_cache_clean_up(struct mail_cache_db * cache_db_env,
    struct mail_cache_db * cache_db_flags,
    struct mailmessage_list * env_list)
{
  chash * hash_exist;
  int res;
  int r;
  char keyname[PATH_MAX];
  unsigned int i;
  
  /* flush cache */
  
  hash_exist = chash_new(CHASH_DEFAULTSIZE, CHASH_COPYALL);
  if (hash_exist == NULL) {
    res = MAIL_ERROR_MEMORY;
    goto err;
  }

  for(i = 0 ; i < carray_count(env_list->msg_tab) ; i ++) {
    mailmessage * msg;
    chashdatum key;
    chashdatum value;

    msg = carray_get(env_list->msg_tab, i);
    
    value.data = NULL;
    value.len = 0;
    
    if (cache_db_env != NULL) {
      snprintf(keyname, PATH_MAX, "%s-envelope", msg->msg_uid);
      
      key.data = keyname;
      key.len = strlen(keyname);
      r = chash_set(hash_exist, &key, &value, NULL);
      if (r < 0) {
        res = MAIL_ERROR_MEMORY;
        goto free;
      }
    }
        
    if (cache_db_flags != NULL) {
      snprintf(keyname, PATH_MAX, "%s-flags", msg->msg_uid);
      
      key.data = keyname;
      key.len = strlen(keyname);
      r = chash_set(hash_exist, &key, &value, NULL);
      if (r < 0) {
        res = MAIL_ERROR_MEMORY;
        goto free;
      }
    }
  }
  
  /* clean up */
  if (cache_db_env != NULL)
    mail_cache_db_clean_up(cache_db_env, hash_exist);
  if (cache_db_flags != NULL)
    mail_cache_db_clean_up(cache_db_flags, hash_exist);
  
  chash_free(hash_exist);
  
  return MAIL_NO_ERROR;

 free:
  chash_free(hash_exist);
 err:
  return res;
}
Ejemplo n.º 25
0
int mailmh_folder_add_message_uid(struct mailmh_folder * folder,
    const char * message, size_t size,
    uint32_t * pindex)
{
  char * tmpname;
  int fd;
  size_t namesize;
  size_t left;
  ssize_t res;
  struct mailmh_msg_info * msg_info;
  uint32_t indx;
  int error;
  int r;
  unsigned int array_index;
  struct stat buf;
  chashdatum key;
  chashdatum data;

  namesize = strlen(folder->fl_filename) + 20;
  tmpname = malloc(namesize);
  snprintf(tmpname, namesize, "%s%ctmpXXXXXX",
	   folder->fl_filename, MAIL_DIR_SEPARATOR);
  fd = mkstemp(tmpname);
  if (fd < 0) {
    error = MAILMH_ERROR_FILE;
    goto free;
  }

  left = size;
  while (left > 0) {
    res = write(fd, message, left);
    if (res == -1) {
      close(fd);
      error = MAILMH_ERROR_FILE;
      goto free;
    }

    left -= res;
  }
  close(fd);

  r = stat(tmpname, &buf);
  if (r < 0) {
    error = MAILMH_ERROR_FILE;
    goto free;
  }

  r = mailmh_folder_alloc_msg(folder, tmpname, &indx);
  if (r != MAILMH_NO_ERROR) {
    unlink(tmpname);
    error = MAILMH_ERROR_COULD_NOT_ALLOC_MSG;
    goto free;
  }
  free(tmpname);

  msg_info = mailmh_msg_info_new(indx, size, buf.st_mtime);
  if (msg_info == NULL) {
    mailmh_folder_remove_message(folder, indx);
    error = MAILMH_ERROR_MEMORY;
    goto err;
  }
  
  r = carray_add(folder->fl_msgs_tab, msg_info, &array_index);
  if (r < 0) {
    mailmh_folder_remove_message(folder, indx);
    mailmh_msg_info_free(msg_info);
    error = MAILMH_ERROR_MEMORY;
    goto err;
  }
  msg_info->msg_array_index = array_index;

  key.data = &indx;
  key.len = sizeof(indx);
  data.data = msg_info;
  data.len = 0;
  
  if (pindex != NULL)
    * pindex = indx;
  
  r = chash_set(folder->fl_msgs_hash, &key, &data, NULL);
  if (r < 0) {
    carray_delete_fast(folder->fl_msgs_tab, msg_info->msg_array_index);
    mailmh_msg_info_free(msg_info);
    error = MAILMH_ERROR_MEMORY;
    goto err;
  }
  
  return MAILMH_NO_ERROR;

 free:
  free(tmpname);
 err:
  return error;
}
Ejemplo n.º 26
0
int maildriver_message_cache_clean_up(char * cache_dir,
    struct mailmessage_list * env_list,
    void (* get_uid_from_filename)(char *))
{
  chash * hash_exist;
  DIR * d;
  char cached_filename[PATH_MAX];
  struct dirent * ent;
  char keyname[PATH_MAX];
  unsigned int i;
  int res;
  int r;
  
  /* remove files */
    
  hash_exist = chash_new(CHASH_DEFAULTSIZE, CHASH_COPYALL);
  if (hash_exist == NULL) {
    res = MAIL_ERROR_MEMORY;
    goto err;
  }
  
  for(i = 0 ; i < carray_count(env_list->msg_tab) ; i ++) {
    mailmessage * msg;
    chashdatum key;
    chashdatum value;
    
    msg = carray_get(env_list->msg_tab, i);
      
    key.data = msg->msg_uid;
    key.len = strlen(msg->msg_uid);
    value.data = NULL;
    value.len = 0;
    r = chash_set(hash_exist, &key, &value, NULL);
    if (r < 0) {
      res = MAIL_ERROR_MEMORY;
      goto free;
    }
  }
  
  d = opendir(cache_dir);
  while ((ent = readdir(d)) != NULL) {
    chashdatum key;
    chashdatum value;
    
    if (strcmp(ent->d_name, ".") == 0)
      continue;
    
    if (strcmp(ent->d_name, "..") == 0)
      continue;
      
    if (strstr(ent->d_name, ".db") != NULL)
      continue;
    
    strncpy(keyname, ent->d_name, sizeof(keyname));
    keyname[sizeof(keyname) - 1] = '\0';
    
    get_uid_from_filename(keyname);
    
    if (* keyname == '\0')
      continue;
    
    key.data = keyname;
    key.len = strlen(keyname);
    
    r = chash_get(hash_exist, &key, &value);
    if (r < 0) {
      snprintf(cached_filename, sizeof(cached_filename),
          "%s/%s", cache_dir, ent->d_name);
      unlink(cached_filename);
    }
  }
  closedir(d);
    
  chash_free(hash_exist);
  
  return MAIL_NO_ERROR;

 free:
  chash_free(hash_exist);
 err:
  return res;
}
Ejemplo n.º 27
0
int mailmh_folder_update(struct mailmh_folder * folder)
{
  DIR * d;
  struct dirent * ent;
  struct stat buf;
  char * mh_seq;
  char filename[PATH_MAX];
  int res;
  int r;
  uint32_t max_index;
  unsigned int i;

  if (stat(folder->fl_filename, &buf) == -1) {
    res = MAILMH_ERROR_FOLDER;
    goto err;
  }

  if (folder->fl_mtime == buf.st_mtime) {
    res = MAILMH_NO_ERROR;
    goto err;
  }

  folder->fl_mtime = buf.st_mtime;

  d = opendir(folder->fl_filename);
  if (d == NULL) {
    res = MAILMH_ERROR_FOLDER;
    goto err;
  }

  max_index = 0;

  /* clear the message list */

  for(i = 0 ; i < carray_count(folder->fl_msgs_tab) ; i ++) {
    struct mailmh_msg_info * msg_info;
    chashdatum key;
    
    msg_info = carray_get(folder->fl_msgs_tab, i);
    if (msg_info == NULL)
      continue;

    key.data = &msg_info->msg_index;
    key.len = sizeof(msg_info->msg_index);
    chash_delete(folder->fl_msgs_hash, &key, NULL);
    
    mailmh_msg_info_free(msg_info);
  }

  carray_set_size(folder->fl_msgs_tab, 0);

  do {
    uint32_t indx;

    ent = readdir(d);

    if (ent != NULL) {

      snprintf(filename, PATH_MAX,
	       "%s%c%s", folder->fl_filename, MAIL_DIR_SEPARATOR, ent->d_name);

      if (stat(filename, &buf) == -1)
	continue;

      if (S_ISREG(buf.st_mode)) {
	indx = strtoul(ent->d_name, NULL, 10);
	if (indx != 0) {
	  struct mailmh_msg_info * msg_info;
	  unsigned int array_index;
          chashdatum key;
          chashdatum data;

	  msg_info = mailmh_msg_info_new(indx, buf.st_size, buf.st_mtime);
	  if (msg_info == NULL) {
	    res = MAILMH_ERROR_MEMORY;
	    goto closedir;
	  }
	  
	  r = carray_add(folder->fl_msgs_tab, msg_info, &array_index);
	  if (r < 0) {
	    mailmh_msg_info_free(msg_info);
	    res = MAILMH_ERROR_MEMORY;
	    goto closedir;
	  }
	  msg_info->msg_array_index = array_index;

	  if (indx > max_index)
	    max_index = indx;

          key.data = &msg_info->msg_index;
          key.len = sizeof(msg_info->msg_index);
          data.data = msg_info;
          data.len = 0;
          
          r = chash_set(folder->fl_msgs_hash, &key, &data, NULL);
	  if (r < 0) {
	    carray_delete_fast(folder->fl_msgs_tab, msg_info->msg_array_index);
	    mailmh_msg_info_free(msg_info);
	    res = MAILMH_ERROR_MEMORY;
	    goto closedir;
	  }
	}
      }
      else if (S_ISDIR(buf.st_mode)) {
	struct mailmh_folder * subfolder;
	unsigned int array_index;
	chashdatum key;
	chashdatum data;

	if (ent->d_name[0] == '.') {
	  if (ent->d_name[1] == 0)
	    continue;
	  if ((ent->d_name[1] == '.') && (ent->d_name[2] == 0))
	    continue;
	}

	key.data = ent->d_name;
	key.len = strlen(ent->d_name);
	r = chash_get(folder->fl_subfolders_hash, &key, &data);
	if (r < 0) {
	  subfolder = mailmh_folder_new(folder, ent->d_name);
	  if (subfolder == NULL) {
	    res = MAILMH_ERROR_MEMORY;
	    goto closedir;
	  }
	  
	  r = carray_add(folder->fl_subfolders_tab, subfolder, &array_index);
	  if (r < 0) {
	    mailmh_folder_free(subfolder);
	    res = MAILMH_ERROR_MEMORY;
	    goto closedir;
	  }
	  subfolder->fl_array_index = array_index;
	  
	  key.data = subfolder->fl_filename;
	  key.len = strlen(subfolder->fl_filename);
	  data.data = subfolder;
	  data.len = 0;
	  r = chash_set(folder->fl_subfolders_hash, &key, &data, NULL);
	  if (r < 0) {
	    carray_delete_fast(folder->fl_subfolders_tab, subfolder->fl_array_index);
	    mailmh_folder_free(subfolder);
	    res = MAILMH_ERROR_MEMORY;
	    goto closedir;
	  }
	}
      }
    }
  }
  while (ent != NULL);

  folder->fl_max_index = max_index;

  mh_seq = malloc(strlen(folder->fl_filename) + 2 + sizeof(".mh_sequences"));
  if (mh_seq == NULL) {
    res = MAILMH_ERROR_MEMORY;
    goto closedir;
  }
  strcpy(mh_seq, folder->fl_filename);
  strcat(mh_seq, MAIL_DIR_SEPARATOR_S);
  strcat(mh_seq, ".mh_sequences");

  if (stat(mh_seq, &buf) == -1) {
    int fd;

    fd = creat(mh_seq, S_IRUSR | S_IWUSR);
    if (fd != -1)
      close(fd);
  }
  free(mh_seq);

  closedir(d);

  return MAILMH_NO_ERROR;

 closedir:
  closedir(d);
 err:
  return res;
}