1 Return-Path: <Sebastian@SSpaeth.de>
\r
2 X-Original-To: notmuch@notmuchmail.org
\r
3 Delivered-To: notmuch@notmuchmail.org
\r
4 Received: from localhost (localhost [127.0.0.1])
\r
5 by olra.theworths.org (Postfix) with ESMTP id D209D4196F3
\r
6 for <notmuch@notmuchmail.org>; Wed, 21 Apr 2010 07:11:22 -0700 (PDT)
\r
7 X-Virus-Scanned: Debian amavisd-new at olra.theworths.org
\r
11 X-Spam-Status: No, score=-1.9 tagged_above=-999 required=5
\r
12 tests=[BAYES_00=-1.9] autolearn=ham
\r
13 Received: from olra.theworths.org ([127.0.0.1])
\r
14 by localhost (olra.theworths.org [127.0.0.1]) (amavisd-new, port 10024)
\r
15 with ESMTP id svf-4VNHV8ST for <notmuch@notmuchmail.org>;
\r
16 Wed, 21 Apr 2010 07:11:17 -0700 (PDT)
\r
17 Received: from homiemail-a13.g.dreamhost.com (caiajhbdcagg.dreamhost.com
\r
19 by olra.theworths.org (Postfix) with ESMTP id 7F2CB431FC1
\r
20 for <notmuch@notmuchmail.org>; Wed, 21 Apr 2010 07:11:17 -0700 (PDT)
\r
21 Received: from sspaeth.de (unknown [195.190.188.219])
\r
22 by homiemail-a13.g.dreamhost.com (Postfix) with ESMTPA id B3EA06A806B;
\r
23 Wed, 21 Apr 2010 07:11:13 -0700 (PDT)
\r
24 Received: by sspaeth.de (sSMTP sendmail emulation);
\r
25 Wed, 21 Apr 2010 16:11:09 +0200
\r
26 From: "Sebastian Spaeth" <Sebastian@SSpaeth.de>
\r
27 To: Dirk Hohndel <hohndel@infradead.org>,
\r
28 Notmuch development list <notmuch@notmuchmail.org>
\r
29 Subject: Re: Address completion
\r
30 In-Reply-To: <871ve9jkhy.fsf@SSpaeth.de>
\r
31 References: <87bpddg67c.fsf@SSpaeth.de> <m3zl0xtqhf.fsf@x200.gr8dns.org>
\r
32 <871ve9jkhy.fsf@SSpaeth.de>
\r
33 Date: Wed, 21 Apr 2010 16:11:09 +0200
\r
34 Message-ID: <878w8gj3pe.fsf@SSpaeth.de>
\r
36 Content-Type: multipart/mixed; boundary="=-=-="
\r
37 X-BeenThere: notmuch@notmuchmail.org
\r
38 X-Mailman-Version: 2.1.13
\r
40 List-Id: "Use and development of the notmuch mail system."
\r
41 <notmuch.notmuchmail.org>
\r
42 List-Unsubscribe: <http://notmuchmail.org/mailman/options/notmuch>,
\r
43 <mailto:notmuch-request@notmuchmail.org?subject=unsubscribe>
\r
44 List-Archive: <http://notmuchmail.org/pipermail/notmuch>
\r
45 List-Post: <mailto:notmuch@notmuchmail.org>
\r
46 List-Help: <mailto:notmuch-request@notmuchmail.org?subject=help>
\r
47 List-Subscribe: <http://notmuchmail.org/mailman/listinfo/notmuch>,
\r
48 <mailto:notmuch-request@notmuchmail.org?subject=subscribe>
\r
49 X-List-Received-Date: Wed, 21 Apr 2010 14:11:23 -0000
\r
53 David improved the notmuch-address.el glue today, and I improved my
\r
54 addrlookup tool also. It is much more intelligent now:
\r
56 We parse the notmuch db in up to 3 passes now where each find from
\r
57 the previous pass is sorted with heigher weight, ie we will first output
\r
58 addresses in our "address book" then addresses we have mailed to
\r
59 previously and only than at mails we have received.
\r
61 1st pass: Find all 'from' addresses that are in messages tagged as
\r
62 'addressbook' (this tag is configurable in .notmuch-config under
\r
63 [user] addrbook_tag=foo but uses addressbook by default)
\r
65 2nd pass: Find all 'to','cc','bcc' addresses that match our criteria and
\r
66 that we ever sent a mail from our primary mail address
\r
68 3rd pass: If pass1 + 2 lead to less than 10 message hits, perform a pass
\r
69 3. Look at all email 'from' headers that match our criteria and
\r
70 use those. We limit this, because notmuch opens all mail files
\r
71 that might match, to read the header out of them, potentially
\r
72 hurting performance a lot. So don't do pass 3 if pass 1 & 2 lead
\r
73 to likely results already.
\r
75 Using the address book feature, you can implement simple 'blacklisting'
\r
76 of emails. If you have friends at Sun for example, you might want to
\r
77 'notmuch tag +addressbook from:"oracle.com"' to give those addresses
\r
78 priority over the sun.com addresses you have previously used.
\r
80 Performance is still good enough. Doing a "addrlookup" which returns everyone
\r
81 in my "addressbook" and all mail addresses I ever sent mail to (just
\r
82 165), takes real 0m0.095s with a warm file cache. If the file cache is
\r
83 cold, a search for e.g. "he" can take real 0m2.385s. The reason is
\r
84 that notmuch opens all possibly matching mail files in order to retrieve
\r
87 Compile directly from vala or the attached c source. Compiling the c source works with glib2.0-dev installed:
\r
89 cc -o addrlookup addrlookup.c `pkg-config --cflags --libs gobject-2.0`
\r
94 Content-Type: text/x-csrc
\r
95 Content-Disposition: attachment; filename=addrlookup.c
\r
96 Content-Description: c source file
\r
98 /* addrlookup.c generated by valac, the Vala compiler
\r
99 * generated from addrlookup.vala, do not modify */
\r
103 #include <glib-object.h>
\r
104 #include <notmuch.h>
\r
105 #include <stdlib.h>
\r
106 #include <string.h>
\r
108 #include <gobject/gvaluecollector.h>
\r
111 #define TYPE_ADDRESS_MATCHER (address_matcher_get_type ())
\r
112 #define ADDRESS_MATCHER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TYPE_ADDRESS_MATCHER, AddressMatcher))
\r
113 #define ADDRESS_MATCHER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TYPE_ADDRESS_MATCHER, AddressMatcherClass))
\r
114 #define IS_ADDRESS_MATCHER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TYPE_ADDRESS_MATCHER))
\r
115 #define IS_ADDRESS_MATCHER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TYPE_ADDRESS_MATCHER))
\r
116 #define ADDRESS_MATCHER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), TYPE_ADDRESS_MATCHER, AddressMatcherClass))
\r
118 typedef struct _AddressMatcher AddressMatcher;
\r
119 typedef struct _AddressMatcherClass AddressMatcherClass;
\r
120 typedef struct _AddressMatcherPrivate AddressMatcherPrivate;
\r
121 #define _notmuch_database_close0(var) ((var == NULL) ? NULL : (var = (notmuch_database_close (var), NULL)))
\r
122 #define _g_free0(var) (var = (g_free (var), NULL))
\r
123 #define _g_error_free0(var) ((var == NULL) ? NULL : (var = (g_error_free (var), NULL)))
\r
124 #define _g_key_file_free0(var) ((var == NULL) ? NULL : (var = (g_key_file_free (var), NULL)))
\r
126 #define ADDRESS_MATCHER_TYPE_MAILADDRESS_FREQ (address_matcher_mailaddress_freq_get_type ())
\r
127 typedef struct _AddressMatcherMailAddress_freq AddressMatcherMailAddress_freq;
\r
128 #define _g_list_free0(var) ((var == NULL) ? NULL : (var = (g_list_free (var), NULL)))
\r
129 #define _g_hash_table_unref0(var) ((var == NULL) ? NULL : (var = (g_hash_table_unref (var), NULL)))
\r
130 #define _g_regex_unref0(var) ((var == NULL) ? NULL : (var = (g_regex_unref (var), NULL)))
\r
131 #define _g_match_info_free0(var) ((var == NULL) ? NULL : (var = (g_match_info_free (var), NULL)))
\r
132 #define _0(var) ((var == NULL) ? NULL : (var = ( (var), NULL)))
\r
133 #define _address_matcher_mailaddress_freq_free0(var) ((var == NULL) ? NULL : (var = (address_matcher_mailaddress_freq_free (var), NULL)))
\r
134 #define __g_list_free_address_matcher_mailaddress_freq_free0(var) ((var == NULL) ? NULL : (var = (_g_list_free_address_matcher_mailaddress_freq_free (var), NULL)))
\r
135 #define _g_string_free0(var) ((var == NULL) ? NULL : (var = (g_string_free (var, TRUE), NULL)))
\r
136 typedef struct _ParamSpecAddressMatcher ParamSpecAddressMatcher;
\r
137 #define _address_matcher_unref0(var) ((var == NULL) ? NULL : (var = (address_matcher_unref (var), NULL)))
\r
139 struct _AddressMatcher {
\r
140 GTypeInstance parent_instance;
\r
141 volatile int ref_count;
\r
142 AddressMatcherPrivate * priv;
\r
145 struct _AddressMatcherClass {
\r
146 GTypeClass parent_class;
\r
147 void (*finalize) (AddressMatcher *self);
\r
150 struct _AddressMatcherPrivate {
\r
151 notmuch_database_t* db;
\r
152 char* user_db_path;
\r
153 char* user_primary_email;
\r
154 char* user_addrbook_tag;
\r
157 struct _AddressMatcherMailAddress_freq {
\r
160 gint occurances_length1;
\r
161 gint _occurances_size_;
\r
164 struct _ParamSpecAddressMatcher {
\r
165 GParamSpec parent_instance;
\r
169 static gpointer address_matcher_parent_class = NULL;
\r
171 gpointer address_matcher_ref (gpointer instance);
\r
172 void address_matcher_unref (gpointer instance);
\r
173 GParamSpec* param_spec_address_matcher (const gchar* name, const gchar* nick, const gchar* blurb, GType object_type, GParamFlags flags);
\r
174 void value_set_address_matcher (GValue* value, gpointer v_object);
\r
175 void value_take_address_matcher (GValue* value, gpointer v_object);
\r
176 gpointer value_get_address_matcher (const GValue* value);
\r
177 GType address_matcher_get_type (void);
\r
178 #define ADDRESS_MATCHER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), TYPE_ADDRESS_MATCHER, AddressMatcherPrivate))
\r
180 ADDRESS_MATCHER_DUMMY_PROPERTY
\r
182 AddressMatcher* address_matcher_new (void);
\r
183 AddressMatcher* address_matcher_construct (GType object_type);
\r
184 static GType address_matcher_mailaddress_freq_get_type (void) G_GNUC_UNUSED;
\r
185 static AddressMatcherMailAddress_freq* address_matcher_mailaddress_freq_dup (const AddressMatcherMailAddress_freq* self);
\r
186 static void address_matcher_mailaddress_freq_free (AddressMatcherMailAddress_freq* self);
\r
187 static void address_matcher_mailaddress_freq_copy (const AddressMatcherMailAddress_freq* self, AddressMatcherMailAddress_freq* dest);
\r
188 static void address_matcher_mailaddress_freq_destroy (AddressMatcherMailAddress_freq* self);
\r
189 static gint address_matcher_sort_by_freq (AddressMatcherMailAddress_freq* mail1, AddressMatcherMailAddress_freq* mail2);
\r
190 char* address_matcher_frequent_fullname (AddressMatcher* self, GHashTable* frequencies);
\r
191 GHashTable* address_matcher_addresses_by_frequency (AddressMatcher* self, notmuch_messages_t* msgs, const char* name, guint pass, GHashTable** addr2realname);
\r
192 static void _vala_array_add1 (char*** array, int* length, int* size, char* value);
\r
193 static void _g_list_free_address_matcher_mailaddress_freq_free (GList* self);
\r
194 char** address_matcher_search_address_passes (AddressMatcher* self, notmuch_query_t** queries, int queries_length1, const char* name, int* result_length1);
\r
195 static void _vala_array_add2 (notmuch_query_t*** array, int* length, int* size, notmuch_query_t* value);
\r
196 static void _vala_array_add3 (notmuch_query_t*** array, int* length, int* size, notmuch_query_t* value);
\r
197 static void _vala_array_add4 (notmuch_query_t*** array, int* length, int* size, notmuch_query_t* value);
\r
198 void address_matcher_run (AddressMatcher* self, const char* name);
\r
199 static guint* _vala_array_dup1 (guint* self, int length);
\r
200 static void address_matcher_finalize (AddressMatcher* obj);
\r
201 gint _vala_main (char** args, int args_length1);
\r
202 static void _vala_array_destroy (gpointer array, gint array_length, GDestroyNotify destroy_func);
\r
203 static void _vala_array_free (gpointer array, gint array_length, GDestroyNotify destroy_func);
\r
207 AddressMatcher* address_matcher_construct (GType object_type) {
\r
208 GError * _inner_error_;
\r
209 AddressMatcher* self;
\r
212 _inner_error_ = NULL;
\r
213 self = (AddressMatcher*) g_type_create_instance (object_type);
\r
214 config = g_key_file_new ();
\r
215 home = g_strdup (g_getenv ("NOTMUCH_CONFIG"));
\r
216 if (home == NULL) {
\r
218 home = (_tmp0_ = g_strdup (g_get_home_dir ()), _g_free0 (home), _tmp0_);
\r
224 g_key_file_load_from_file (config, _tmp1_ = g_strconcat (home, "/.notmuch-config", NULL), G_KEY_FILE_NONE, &_inner_error_);
\r
226 if (_inner_error_ != NULL) {
\r
227 goto __catch0_g_error;
\r
229 _tmp2_ = g_key_file_get_string (config, "database", "path", &_inner_error_);
\r
230 if (_inner_error_ != NULL) {
\r
231 goto __catch0_g_error;
\r
233 self->priv->user_db_path = (_tmp3_ = _tmp2_, _g_free0 (self->priv->user_db_path), _tmp3_);
\r
239 ex = _inner_error_;
\r
240 _inner_error_ = NULL;
\r
242 _g_error_free0 (ex);
\r
246 if (_inner_error_ != NULL) {
\r
247 _g_key_file_free0 (config);
\r
249 g_critical ("file %s: line %d: uncaught error: %s (%s, %d)", __FILE__, __LINE__, _inner_error_->message, g_quark_to_string (_inner_error_->domain), _inner_error_->code);
\r
250 g_clear_error (&_inner_error_);
\r
256 _tmp4_ = g_key_file_get_string (config, "user", "primary_email", &_inner_error_);
\r
257 if (_inner_error_ != NULL) {
\r
258 goto __catch1_g_error;
\r
260 self->priv->user_primary_email = (_tmp5_ = _tmp4_, _g_free0 (self->priv->user_primary_email), _tmp5_);
\r
266 ex = _inner_error_;
\r
267 _inner_error_ = NULL;
\r
269 _g_error_free0 (ex);
\r
273 if (_inner_error_ != NULL) {
\r
274 _g_key_file_free0 (config);
\r
276 g_critical ("file %s: line %d: uncaught error: %s (%s, %d)", __FILE__, __LINE__, _inner_error_->message, g_quark_to_string (_inner_error_->domain), _inner_error_->code);
\r
277 g_clear_error (&_inner_error_);
\r
283 _tmp6_ = g_key_file_get_string (config, "user", "addrbook_tag", &_inner_error_);
\r
284 if (_inner_error_ != NULL) {
\r
285 goto __catch2_g_error;
\r
287 self->priv->user_addrbook_tag = (_tmp7_ = _tmp6_, _g_free0 (self->priv->user_addrbook_tag), _tmp7_);
\r
293 ex = _inner_error_;
\r
294 _inner_error_ = NULL;
\r
297 self->priv->user_addrbook_tag = (_tmp8_ = g_strdup ("addressbook"), _g_free0 (self->priv->user_addrbook_tag), _tmp8_);
\r
298 _g_error_free0 (ex);
\r
302 if (_inner_error_ != NULL) {
\r
303 _g_key_file_free0 (config);
\r
305 g_critical ("file %s: line %d: uncaught error: %s (%s, %d)", __FILE__, __LINE__, _inner_error_->message, g_quark_to_string (_inner_error_->domain), _inner_error_->code);
\r
306 g_clear_error (&_inner_error_);
\r
309 _g_key_file_free0 (config);
\r
315 AddressMatcher* address_matcher_new (void) {
\r
316 return address_matcher_construct (TYPE_ADDRESS_MATCHER);
\r
320 static gint address_matcher_sort_by_freq (AddressMatcherMailAddress_freq* mail1, AddressMatcherMailAddress_freq* mail2) {
\r
322 gboolean _tmp0_ = FALSE;
\r
323 gboolean _tmp1_ = FALSE;
\r
324 gboolean _tmp2_ = FALSE;
\r
325 gboolean _tmp3_ = FALSE;
\r
326 if ((*mail1).occurances[0] == (*mail2).occurances[0]) {
\r
327 _tmp1_ = (*mail1).occurances[1] == (*mail2).occurances[1];
\r
332 _tmp0_ = (*mail1).occurances[2] == (*mail2).occurances[2];
\r
340 if ((*mail1).occurances[0] > (*mail2).occurances[0]) {
\r
343 gboolean _tmp4_ = FALSE;
\r
344 if ((*mail1).occurances[0] == (*mail2).occurances[0]) {
\r
345 _tmp4_ = (*mail1).occurances[1] > (*mail2).occurances[1];
\r
354 gboolean _tmp5_ = FALSE;
\r
355 gboolean _tmp6_ = FALSE;
\r
356 if ((*mail1).occurances[0] == (*mail2).occurances[0]) {
\r
357 _tmp6_ = (*mail1).occurances[1] == (*mail2).occurances[1];
\r
362 _tmp5_ = (*mail1).occurances[2] > (*mail2).occurances[2];
\r
377 static gboolean string_contains (const char* self, const char* needle) {
\r
378 gboolean result = FALSE;
\r
379 g_return_val_if_fail (self != NULL, FALSE);
\r
380 g_return_val_if_fail (needle != NULL, FALSE);
\r
381 result = strstr (self, needle) != NULL;
\r
386 char* address_matcher_frequent_fullname (AddressMatcher* self, GHashTable* frequencies) {
\r
387 char* result = NULL;
\r
390 g_return_val_if_fail (self != NULL, NULL);
\r
391 g_return_val_if_fail (frequencies != NULL, NULL);
\r
392 maxfreq = (guint) 0;
\r
395 GList* mail_collection;
\r
397 mail_collection = g_hash_table_get_keys (frequencies);
\r
398 for (mail_it = mail_collection; mail_it != NULL; mail_it = mail_it->next) {
\r
400 mail = (const char*) mail_it->data;
\r
403 gboolean _tmp0_ = FALSE;
\r
404 gboolean _tmp1_ = FALSE;
\r
405 freq = GPOINTER_TO_UINT (g_hash_table_lookup (frequencies, mail));
\r
406 if (freq > maxfreq) {
\r
407 _tmp1_ = string_contains (mail, " ");
\r
414 _tmp0_ = g_hash_table_size (frequencies) == 1;
\r
419 fullname = (_tmp2_ = g_strdup (mail), _g_free0 (fullname), _tmp2_);
\r
423 _g_list_free0 (mail_collection);
\r
430 static gpointer _g_hash_table_ref0 (gpointer self) {
\r
431 return self ? g_hash_table_ref (self) : NULL;
\r
435 GHashTable* address_matcher_addresses_by_frequency (AddressMatcher* self, notmuch_messages_t* msgs, const char* name, guint pass, GHashTable** addr2realname) {
\r
436 GHashTable* result = NULL;
\r
437 GError * _inner_error_;
\r
441 gint _headers_size_;
\r
442 gint headers_length1;
\r
443 char** _tmp2_ = NULL;
\r
445 g_return_val_if_fail (self != NULL, NULL);
\r
446 g_return_val_if_fail (msgs != NULL, NULL);
\r
447 g_return_val_if_fail (name != NULL, NULL);
\r
448 g_return_val_if_fail (addr2realname != NULL, NULL);
\r
449 _inner_error_ = NULL;
\r
450 ht = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
\r
455 _tmp0_ = g_regex_new ("\\s*((\\\"(\\\\.|[^\\\\\"])*\\\"|[^,])*" "<?(?P<mail>\\b\\w+([-+.]\\w+)*\\@\\w+[-\\.\\w]*\\.([-\\.\\w]+)*\\w\\b)" \
\r
456 ">?)", 0, 0, &_inner_error_);
\r
457 if (_inner_error_ != NULL) {
\r
458 if (_inner_error_->domain == G_REGEX_ERROR) {
\r
459 goto __catch3_g_regex_error;
\r
461 _g_hash_table_unref0 (ht);
\r
462 _g_regex_unref0 (re);
\r
463 g_critical ("file %s: line %d: unexpected error: %s (%s, %d)", __FILE__, __LINE__, _inner_error_->message, g_quark_to_string (_inner_error_->domain), _inner_error_->code);
\r
464 g_clear_error (&_inner_error_);
\r
467 re = (_tmp1_ = _tmp0_, _g_regex_unref0 (re), _tmp1_);
\r
470 __catch3_g_regex_error:
\r
473 ex = _inner_error_;
\r
474 _inner_error_ = NULL;
\r
476 _g_error_free0 (ex);
\r
480 if (_inner_error_ != NULL) {
\r
481 _g_hash_table_unref0 (ht);
\r
482 _g_regex_unref0 (re);
\r
483 g_critical ("file %s: line %d: uncaught error: %s (%s, %d)", __FILE__, __LINE__, _inner_error_->message, g_quark_to_string (_inner_error_->domain), _inner_error_->code);
\r
484 g_clear_error (&_inner_error_);
\r
487 headers = (_tmp3_ = (_tmp2_ = g_new0 (char*, 1 + 1), _tmp2_[0] = g_strdup ("from"), _tmp2_), headers_length1 = 1, _headers_size_ = headers_length1, _tmp3_);
\r
490 char** _tmp4_ = NULL;
\r
491 headers = (_tmp5_ = (_tmp4_ = g_new0 (char*, 3 + 1), _tmp4_[0] = g_strdup ("to"), _tmp4_[1] = g_strdup ("cc"), _tmp4_[2] = g_strdup ("bcc"), _tmp4_), headers = (_vala_array_free (headers, headers_length1, (GDestroyNotify) g_free), NULL), headers_length1 = 3, _headers_size_ = headers_length1, _tmp5_);
\r
494 GMatchInfo* matches;
\r
495 notmuch_message_t* msg;
\r
496 if (!notmuch_messages_valid (msgs)) {
\r
500 msg = notmuch_messages_get (msgs);
\r
502 char** header_collection;
\r
503 int header_collection_length1;
\r
505 header_collection = headers;
\r
506 header_collection_length1 = headers_length1;
\r
507 for (header_it = 0; header_it < headers_length1; header_it = header_it + 1) {
\r
509 header = g_strdup (header_collection[header_it]);
\r
512 GMatchInfo* _tmp8_;
\r
514 GMatchInfo* _tmp6_ = NULL;
\r
516 froms = g_strdup ((const char*) notmuch_message_get_header (msg, header));
\r
517 found = (_tmp7_ = g_regex_match (re, froms, 0, &_tmp6_), matches = (_tmp8_ = _tmp6_, _g_match_info_free0 (matches), _tmp8_), _tmp7_);
\r
526 GHashTable* realname_freq;
\r
530 from = g_match_info_fetch (matches, 1);
\r
531 addr = g_match_info_fetch_named (matches, "mail");
\r
532 addr = (_tmp9_ = g_utf8_strdown (addr, -1), _g_free0 (addr), _tmp9_);
\r
535 _tmp10_ = g_match_info_next (matches, &_inner_error_);
\r
536 if (_inner_error_ != NULL) {
\r
537 if (_inner_error_->domain == G_REGEX_ERROR) {
\r
538 goto __catch4_g_regex_error;
\r
544 _g_match_info_free0 (matches);
\r
546 _g_hash_table_unref0 (ht);
\r
547 _g_regex_unref0 (re);
\r
548 headers = (_vala_array_free (headers, headers_length1, (GDestroyNotify) g_free), NULL);
\r
549 g_critical ("file %s: line %d: unexpected error: %s (%s, %d)", __FILE__, __LINE__, _inner_error_->message, g_quark_to_string (_inner_error_->domain), _inner_error_->code);
\r
550 g_clear_error (&_inner_error_);
\r
556 __catch4_g_regex_error:
\r
559 ex = _inner_error_;
\r
560 _inner_error_ = NULL;
\r
562 _g_error_free0 (ex);
\r
566 if (_inner_error_ != NULL) {
\r
571 _g_match_info_free0 (matches);
\r
573 _g_hash_table_unref0 (ht);
\r
574 _g_regex_unref0 (re);
\r
575 headers = (_vala_array_free (headers, headers_length1, (GDestroyNotify) g_free), NULL);
\r
576 g_critical ("file %s: line %d: uncaught error: %s (%s, %d)", __FILE__, __LINE__, _inner_error_->message, g_quark_to_string (_inner_error_->domain), _inner_error_->code);
\r
577 g_clear_error (&_inner_error_);
\r
580 is_match = (_tmp12_ = g_regex_match_simple (_tmp11_ = g_strconcat ("\\b", name, NULL), from, G_REGEX_CASELESS, 0), _g_free0 (_tmp11_), _tmp12_);
\r
586 occurs = GPOINTER_TO_UINT (g_hash_table_lookup (ht, addr)) + 1;
\r
587 g_hash_table_replace (ht, g_strdup (addr), GUINT_TO_POINTER (occurs));
\r
588 realname_freq = _g_hash_table_ref0 ((GHashTable*) g_hash_table_lookup (*addr2realname, addr));
\r
589 if (realname_freq == NULL) {
\r
590 GHashTable* _tmp13_;
\r
591 realname_freq = (_tmp13_ = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, NULL), _g_hash_table_unref0 (realname_freq), _tmp13_);
\r
592 g_hash_table_insert (*addr2realname, g_strdup (addr), _g_hash_table_ref0 (realname_freq));
\r
594 occurs = GPOINTER_TO_UINT (g_hash_table_lookup (realname_freq, from)) + 1;
\r
595 g_hash_table_replace (realname_freq, g_strdup (from), GUINT_TO_POINTER (occurs));
\r
598 _g_hash_table_unref0 (realname_freq);
\r
605 notmuch_message_destroy (msg);
\r
606 notmuch_messages_move_to_next (msgs);
\r
607 _g_match_info_free0 (matches);
\r
611 _g_regex_unref0 (re);
\r
612 headers = (_vala_array_free (headers, headers_length1, (GDestroyNotify) g_free), NULL);
\r
617 static gpointer _address_matcher_mailaddress_freq_dup0 (gpointer self) {
\r
618 return self ? address_matcher_mailaddress_freq_dup (self) : NULL;
\r
622 static void _vala_array_add1 (char*** array, int* length, int* size, char* value) {
\r
623 if ((*length) == (*size)) {
\r
624 *size = (*size) ? (2 * (*size)) : 4;
\r
625 *array = g_renew (char*, *array, (*size) + 1);
\r
627 (*array)[(*length)++] = value;
\r
628 (*array)[*length] = NULL;
\r
632 static void _g_list_free_address_matcher_mailaddress_freq_free (GList* self) {
\r
633 g_list_foreach (self, (GFunc) address_matcher_mailaddress_freq_free, NULL);
\r
634 g_list_free (self);
\r
638 char** address_matcher_search_address_passes (AddressMatcher* self, notmuch_query_t** queries, int queries_length1, const char* name, int* result_length1) {
\r
639 char** result = NULL;
\r
641 gint _return_value_size_;
\r
642 gint return_value_length1;
\r
643 char** return_value;
\r
644 GHashTable* addrfreq;
\r
645 GHashTable* addr2realname;
\r
649 g_return_val_if_fail (self != NULL, NULL);
\r
650 g_return_val_if_fail (name != NULL, NULL);
\r
651 return_value = (_tmp0_ = NULL, return_value_length1 = 0, _return_value_size_ = return_value_length1, _tmp0_);
\r
652 addrfreq = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
\r
653 addr2realname = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
\r
656 notmuch_query_t** q_collection;
\r
657 int q_collection_length1;
\r
659 q_collection = queries;
\r
660 q_collection_length1 = queries_length1;
\r
661 for (q_it = 0; q_it < queries_length1; q_it = q_it + 1) {
\r
662 notmuch_query_t* q;
\r
663 q = q_collection[q_it];
\r
665 notmuch_messages_t* msgs;
\r
667 msgs = notmuch_query_search_messages (q);
\r
668 ht = address_matcher_addresses_by_frequency (self, msgs, name, pass, &addr2realname);
\r
670 GList* addr_collection;
\r
672 addr_collection = g_hash_table_get_keys (ht);
\r
673 for (addr_it = addr_collection; addr_it != NULL; addr_it = addr_it->next) {
\r
675 addr = (const char*) addr_it->data;
\r
677 AddressMatcherMailAddress_freq* freq;
\r
678 freq = _address_matcher_mailaddress_freq_dup0 ((AddressMatcherMailAddress_freq*) g_hash_table_lookup (addrfreq, addr));
\r
679 if (freq == NULL) {
\r
680 AddressMatcherMailAddress_freq* _tmp5_;
\r
681 AddressMatcherMailAddress_freq _tmp4_;
\r
682 AddressMatcherMailAddress_freq _tmp3_;
\r
683 guint* _tmp1_ = NULL;
\r
684 AddressMatcherMailAddress_freq _tmp2_ = {0};
\r
685 freq = (_tmp5_ = _address_matcher_mailaddress_freq_dup0 ((_tmp4_ = _tmp3_ = (memset (&_tmp2_, 0, sizeof (AddressMatcherMailAddress_freq)), _tmp2_.address = g_strdup (addr), _tmp2_.occurances = (_tmp1_ = g_new0 (guint, 3), _tmp1_[0] = (guint) 0, _tmp1_[1] = (guint) 0, _tmp1_[2] = (guint) 0, _tmp1_), _tmp2_.occurances_length1 = 3, _tmp2_), &_tmp4_)), _address_matcher_mailaddress_freq_free0 (freq), _tmp5_);
\r
686 address_matcher_mailaddress_freq_destroy (&_tmp3_);
\r
688 (*freq).occurances[pass] = GPOINTER_TO_UINT (g_hash_table_lookup (ht, addr));
\r
689 g_hash_table_replace (addrfreq, g_strdup (addr), _address_matcher_mailaddress_freq_dup0 (freq));
\r
690 _address_matcher_mailaddress_freq_free0 (freq);
\r
693 _g_list_free0 (addr_collection);
\r
695 notmuch_messages_destroy (msgs);
\r
696 pass = pass + ((guint) 1);
\r
698 _g_hash_table_unref0 (ht);
\r
702 addrs = g_hash_table_get_values (addrfreq);
\r
703 addrs = g_list_sort (addrs, (GCompareFunc) address_matcher_sort_by_freq);
\r
705 GList* addr_collection;
\r
707 addr_collection = addrs;
\r
708 for (addr_it = addr_collection; addr_it != NULL; addr_it = addr_it->next) {
\r
709 AddressMatcherMailAddress_freq* addr;
\r
710 addr = _address_matcher_mailaddress_freq_dup0 ((AddressMatcherMailAddress_freq*) addr_it->data);
\r
713 freqs = _g_hash_table_ref0 ((GHashTable*) g_hash_table_lookup (addr2realname, (*addr).address));
\r
714 _vala_array_add1 (&return_value, &return_value_length1, &_return_value_size_, address_matcher_frequent_fullname (self, freqs));
\r
715 _address_matcher_mailaddress_freq_free0 (addr);
\r
716 _g_hash_table_unref0 (freqs);
\r
720 result = (_tmp6_ = return_value, *result_length1 = return_value_length1, _tmp6_);
\r
721 _g_hash_table_unref0 (addrfreq);
\r
722 _g_hash_table_unref0 (addr2realname);
\r
723 __g_list_free_address_matcher_mailaddress_freq_free0 (addrs);
\r
725 return_value = (_vala_array_free (return_value, return_value_length1, (GDestroyNotify) g_free), NULL);
\r
726 _g_hash_table_unref0 (addrfreq);
\r
727 _g_hash_table_unref0 (addr2realname);
\r
728 __g_list_free_address_matcher_mailaddress_freq_free0 (addrs);
\r
732 static void _vala_array_add2 (notmuch_query_t*** array, int* length, int* size, notmuch_query_t* value) {
\r
733 if ((*length) == (*size)) {
\r
734 *size = (*size) ? (2 * (*size)) : 4;
\r
735 *array = g_renew (notmuch_query_t*, *array, *size);
\r
737 (*array)[(*length)++] = value;
\r
741 static void _vala_array_add3 (notmuch_query_t*** array, int* length, int* size, notmuch_query_t* value) {
\r
742 if ((*length) == (*size)) {
\r
743 *size = (*size) ? (2 * (*size)) : 4;
\r
744 *array = g_renew (notmuch_query_t*, *array, *size);
\r
746 (*array)[(*length)++] = value;
\r
750 static void _vala_array_add4 (notmuch_query_t*** array, int* length, int* size, notmuch_query_t* value) {
\r
751 if ((*length) == (*size)) {
\r
752 *size = (*size) ? (2 * (*size)) : 4;
\r
753 *array = g_renew (notmuch_query_t*, *array, *size);
\r
755 (*array)[(*length)++] = value;
\r
759 void address_matcher_run (AddressMatcher* self, const char* name) {
\r
760 notmuch_query_t** _tmp1_;
\r
761 gint _queries_size_;
\r
762 gint queries_length1;
\r
763 notmuch_query_t** _tmp0_ = NULL;
\r
764 notmuch_query_t** queries;
\r
765 notmuch_database_t* _tmp2_;
\r
771 gint __result__size_;
\r
772 gint _result__length1;
\r
775 g_return_if_fail (self != NULL);
\r
776 queries = (_tmp1_ = (_tmp0_ = g_new0 (notmuch_query_t*, 0), _tmp0_), queries_length1 = 0, _queries_size_ = queries_length1, _tmp1_);
\r
777 self->priv->db = (_tmp2_ = notmuch_database_open (self->priv->user_db_path, NOTMUCH_DATABASE_MODE_READ_ONLY), _notmuch_database_close0 (self->priv->db), _tmp2_);
\r
778 querystr = (_tmp4_ = g_string_new (_tmp3_ = g_strconcat ("tag:", self->priv->user_addrbook_tag, NULL)), _g_free0 (_tmp3_), _tmp4_);
\r
779 if (name != NULL) {
\r
782 g_string_append (querystr, _tmp6_ = g_strconcat (_tmp5_ = g_strconcat (" and from:", name, NULL), "*", NULL));
\r
788 _vala_array_add2 (&queries, &queries_length1, &_queries_size_, notmuch_query_create (self->priv->db, querystr->str));
\r
789 querystr = (_tmp7_ = g_string_new (""), _g_string_free0 (querystr), _tmp7_);
\r
790 if (name != NULL) {
\r
793 g_string_append (querystr, _tmp9_ = g_strconcat (_tmp8_ = g_strconcat ("to:", name, NULL), "*", NULL));
\r
797 if (self->priv->user_primary_email != NULL) {
\r
799 g_string_append (querystr, _tmp10_ = g_strconcat (" from:", self->priv->user_primary_email, NULL));
\r
800 _g_free0 (_tmp10_);
\r
802 _vala_array_add3 (&queries, &queries_length1, &_queries_size_, notmuch_query_create (self->priv->db, querystr->str));
\r
803 if ((notmuch_query_count_messages (queries[0]) + notmuch_query_count_messages (queries[1])) < 10) {
\r
805 querystr = (_tmp11_ = g_string_new (""), _g_string_free0 (querystr), _tmp11_);
\r
806 if (name != NULL) {
\r
809 g_string_append (querystr, _tmp13_ = g_strconcat (_tmp12_ = g_strconcat ("from:", name, NULL), "*", NULL));
\r
810 _g_free0 (_tmp13_);
\r
811 _g_free0 (_tmp12_);
\r
813 _vala_array_add4 (&queries, &queries_length1, &_queries_size_, notmuch_query_create (self->priv->db, querystr->str));
\r
815 _result_ = (_tmp15_ = address_matcher_search_address_passes (self, queries, queries_length1, name, &_tmp14_), _result__length1 = _tmp14_, __result__size_ = _result__length1, _tmp15_);
\r
817 char** name_collection;
\r
818 int name_collection_length1;
\r
820 name_collection = _result_;
\r
821 name_collection_length1 = _result__length1;
\r
822 for (name_it = 0; name_it < _result__length1; name_it = name_it + 1) {
\r
824 name = g_strdup (name_collection[name_it]);
\r
826 fprintf (stdout, "%s\n", name);
\r
831 queries = (g_free (queries), NULL);
\r
832 _g_string_free0 (querystr);
\r
833 _result_ = (_vala_array_free (_result_, _result__length1, (GDestroyNotify) g_free), NULL);
\r
837 static guint* _vala_array_dup1 (guint* self, int length) {
\r
838 return g_memdup (self, length * sizeof (guint));
\r
842 static void address_matcher_mailaddress_freq_copy (const AddressMatcherMailAddress_freq* self, AddressMatcherMailAddress_freq* dest) {
\r
844 dest->address = g_strdup (self->address);
\r
845 dest->occurances = (_tmp0_ = self->occurances, (_tmp0_ == NULL) ? ((gpointer) _tmp0_) : _vala_array_dup1 (_tmp0_, (*self).occurances_length1));
\r
846 dest->occurances_length1 = self->occurances_length1;
\r
850 static void address_matcher_mailaddress_freq_destroy (AddressMatcherMailAddress_freq* self) {
\r
851 _g_free0 (self->address);
\r
852 self->occurances = (g_free (self->occurances), NULL);
\r
856 static AddressMatcherMailAddress_freq* address_matcher_mailaddress_freq_dup (const AddressMatcherMailAddress_freq* self) {
\r
857 AddressMatcherMailAddress_freq* dup;
\r
858 dup = g_new0 (AddressMatcherMailAddress_freq, 1);
\r
859 address_matcher_mailaddress_freq_copy (self, dup);
\r
864 static void address_matcher_mailaddress_freq_free (AddressMatcherMailAddress_freq* self) {
\r
865 address_matcher_mailaddress_freq_destroy (self);
\r
870 static GType address_matcher_mailaddress_freq_get_type (void) {
\r
871 static volatile gsize address_matcher_mailaddress_freq_type_id__volatile = 0;
\r
872 if (g_once_init_enter (&address_matcher_mailaddress_freq_type_id__volatile)) {
\r
873 GType address_matcher_mailaddress_freq_type_id;
\r
874 address_matcher_mailaddress_freq_type_id = g_boxed_type_register_static ("AddressMatcherMailAddress_freq", (GBoxedCopyFunc) address_matcher_mailaddress_freq_dup, (GBoxedFreeFunc) address_matcher_mailaddress_freq_free);
\r
875 g_once_init_leave (&address_matcher_mailaddress_freq_type_id__volatile, address_matcher_mailaddress_freq_type_id);
\r
877 return address_matcher_mailaddress_freq_type_id__volatile;
\r
881 static void value_address_matcher_init (GValue* value) {
\r
882 value->data[0].v_pointer = NULL;
\r
886 static void value_address_matcher_free_value (GValue* value) {
\r
887 if (value->data[0].v_pointer) {
\r
888 address_matcher_unref (value->data[0].v_pointer);
\r
893 static void value_address_matcher_copy_value (const GValue* src_value, GValue* dest_value) {
\r
894 if (src_value->data[0].v_pointer) {
\r
895 dest_value->data[0].v_pointer = address_matcher_ref (src_value->data[0].v_pointer);
\r
897 dest_value->data[0].v_pointer = NULL;
\r
902 static gpointer value_address_matcher_peek_pointer (const GValue* value) {
\r
903 return value->data[0].v_pointer;
\r
907 static gchar* value_address_matcher_collect_value (GValue* value, guint n_collect_values, GTypeCValue* collect_values, guint collect_flags) {
\r
908 if (collect_values[0].v_pointer) {
\r
909 AddressMatcher* object;
\r
910 object = collect_values[0].v_pointer;
\r
911 if (object->parent_instance.g_class == NULL) {
\r
912 return g_strconcat ("invalid unclassed object pointer for value type `", G_VALUE_TYPE_NAME (value), "'", NULL);
\r
913 } else if (!g_value_type_compatible (G_TYPE_FROM_INSTANCE (object), G_VALUE_TYPE (value))) {
\r
914 return g_strconcat ("invalid object type `", g_type_name (G_TYPE_FROM_INSTANCE (object)), "' for value type `", G_VALUE_TYPE_NAME (value), "'", NULL);
\r
916 value->data[0].v_pointer = address_matcher_ref (object);
\r
918 value->data[0].v_pointer = NULL;
\r
924 static gchar* value_address_matcher_lcopy_value (const GValue* value, guint n_collect_values, GTypeCValue* collect_values, guint collect_flags) {
\r
925 AddressMatcher** object_p;
\r
926 object_p = collect_values[0].v_pointer;
\r
928 return g_strdup_printf ("value location for `%s' passed as NULL", G_VALUE_TYPE_NAME (value));
\r
930 if (!value->data[0].v_pointer) {
\r
932 } else if (collect_flags && G_VALUE_NOCOPY_CONTENTS) {
\r
933 *object_p = value->data[0].v_pointer;
\r
935 *object_p = address_matcher_ref (value->data[0].v_pointer);
\r
941 GParamSpec* param_spec_address_matcher (const gchar* name, const gchar* nick, const gchar* blurb, GType object_type, GParamFlags flags) {
\r
942 ParamSpecAddressMatcher* spec;
\r
943 g_return_val_if_fail (g_type_is_a (object_type, TYPE_ADDRESS_MATCHER), NULL);
\r
944 spec = g_param_spec_internal (G_TYPE_PARAM_OBJECT, name, nick, blurb, flags);
\r
945 G_PARAM_SPEC (spec)->value_type = object_type;
\r
946 return G_PARAM_SPEC (spec);
\r
950 gpointer value_get_address_matcher (const GValue* value) {
\r
951 g_return_val_if_fail (G_TYPE_CHECK_VALUE_TYPE (value, TYPE_ADDRESS_MATCHER), NULL);
\r
952 return value->data[0].v_pointer;
\r
956 void value_set_address_matcher (GValue* value, gpointer v_object) {
\r
957 AddressMatcher* old;
\r
958 g_return_if_fail (G_TYPE_CHECK_VALUE_TYPE (value, TYPE_ADDRESS_MATCHER));
\r
959 old = value->data[0].v_pointer;
\r
961 g_return_if_fail (G_TYPE_CHECK_INSTANCE_TYPE (v_object, TYPE_ADDRESS_MATCHER));
\r
962 g_return_if_fail (g_value_type_compatible (G_TYPE_FROM_INSTANCE (v_object), G_VALUE_TYPE (value)));
\r
963 value->data[0].v_pointer = v_object;
\r
964 address_matcher_ref (value->data[0].v_pointer);
\r
966 value->data[0].v_pointer = NULL;
\r
969 address_matcher_unref (old);
\r
974 void value_take_address_matcher (GValue* value, gpointer v_object) {
\r
975 AddressMatcher* old;
\r
976 g_return_if_fail (G_TYPE_CHECK_VALUE_TYPE (value, TYPE_ADDRESS_MATCHER));
\r
977 old = value->data[0].v_pointer;
\r
979 g_return_if_fail (G_TYPE_CHECK_INSTANCE_TYPE (v_object, TYPE_ADDRESS_MATCHER));
\r
980 g_return_if_fail (g_value_type_compatible (G_TYPE_FROM_INSTANCE (v_object), G_VALUE_TYPE (value)));
\r
981 value->data[0].v_pointer = v_object;
\r
983 value->data[0].v_pointer = NULL;
\r
986 address_matcher_unref (old);
\r
991 static void address_matcher_class_init (AddressMatcherClass * klass) {
\r
992 address_matcher_parent_class = g_type_class_peek_parent (klass);
\r
993 ADDRESS_MATCHER_CLASS (klass)->finalize = address_matcher_finalize;
\r
994 g_type_class_add_private (klass, sizeof (AddressMatcherPrivate));
\r
998 static void address_matcher_instance_init (AddressMatcher * self) {
\r
999 self->priv = ADDRESS_MATCHER_GET_PRIVATE (self);
\r
1000 self->priv->user_db_path = NULL;
\r
1001 self->priv->user_primary_email = NULL;
\r
1002 self->priv->user_addrbook_tag = NULL;
\r
1003 self->ref_count = 1;
\r
1007 static void address_matcher_finalize (AddressMatcher* obj) {
\r
1008 AddressMatcher * self;
\r
1009 self = ADDRESS_MATCHER (obj);
\r
1010 _notmuch_database_close0 (self->priv->db);
\r
1011 _g_free0 (self->priv->user_db_path);
\r
1012 _g_free0 (self->priv->user_primary_email);
\r
1013 _g_free0 (self->priv->user_addrbook_tag);
\r
1017 GType address_matcher_get_type (void) {
\r
1018 static volatile gsize address_matcher_type_id__volatile = 0;
\r
1019 if (g_once_init_enter (&address_matcher_type_id__volatile)) {
\r
1020 static const GTypeValueTable g_define_type_value_table = { value_address_matcher_init, value_address_matcher_free_value, value_address_matcher_copy_value, value_address_matcher_peek_pointer, "p", value_address_matcher_collect_value, "p", value_address_matcher_lcopy_value };
\r
1021 static const GTypeInfo g_define_type_info = { sizeof (AddressMatcherClass), (GBaseInitFunc) NULL, (GBaseFinalizeFunc) NULL, (GClassInitFunc) address_matcher_class_init, (GClassFinalizeFunc) NULL, NULL, sizeof (AddressMatcher), 0, (GInstanceInitFunc) address_matcher_instance_init, &g_define_type_value_table };
\r
1022 static const GTypeFundamentalInfo g_define_type_fundamental_info = { (G_TYPE_FLAG_CLASSED | G_TYPE_FLAG_INSTANTIATABLE | G_TYPE_FLAG_DERIVABLE | G_TYPE_FLAG_DEEP_DERIVABLE) };
\r
1023 GType address_matcher_type_id;
\r
1024 address_matcher_type_id = g_type_register_fundamental (g_type_fundamental_next (), "AddressMatcher", &g_define_type_info, &g_define_type_fundamental_info, 0);
\r
1025 g_once_init_leave (&address_matcher_type_id__volatile, address_matcher_type_id);
\r
1027 return address_matcher_type_id__volatile;
\r
1031 gpointer address_matcher_ref (gpointer instance) {
\r
1032 AddressMatcher* self;
\r
1034 g_atomic_int_inc (&self->ref_count);
\r
1039 void address_matcher_unref (gpointer instance) {
\r
1040 AddressMatcher* self;
\r
1042 if (g_atomic_int_dec_and_test (&self->ref_count)) {
\r
1043 ADDRESS_MATCHER_GET_CLASS (self)->finalize (self);
\r
1044 g_type_free_instance ((GTypeInstance *) self);
\r
1049 gint _vala_main (char** args, int args_length1) {
\r
1051 AddressMatcher* app;
\r
1052 app = address_matcher_new ();
\r
1053 address_matcher_run (app, args[1]);
\r
1055 _address_matcher_unref0 (app);
\r
1060 int main (int argc, char ** argv) {
\r
1062 return _vala_main (argv, argc);
\r
1066 static void _vala_array_destroy (gpointer array, gint array_length, GDestroyNotify destroy_func) {
\r
1067 if ((array != NULL) && (destroy_func != NULL)) {
\r
1069 for (i = 0; i < array_length; i = i + 1) {
\r
1070 if (((gpointer*) array)[i] != NULL) {
\r
1071 destroy_func (((gpointer*) array)[i]);
\r
1078 static void _vala_array_free (gpointer array, gint array_length, GDestroyNotify destroy_func) {
\r
1079 _vala_array_destroy (array, array_length, destroy_func);
\r