Prettier dates and From: labels. Initial GMime integration.
This adds a VAPI (including generation files and Makefile) for GMime to the repo, which we'll be using extensively to come. This VAPI is incomplete in many ways, so care should be used going forward. Also, with GMime now interpreting RFC822 dates, can now pretty-print them. Prettier From: names also added this time around.
This commit is contained in:
parent
a581218ea9
commit
ba81ad43a4
15 changed files with 1168 additions and 24 deletions
13
Makefile
13
Makefile
|
|
@ -2,7 +2,7 @@ PROGRAM = geary
|
||||||
BUILD_ROOT = 1
|
BUILD_ROOT = 1
|
||||||
|
|
||||||
VALAC := valac
|
VALAC := valac
|
||||||
VALAFLAGS := -g --save-temps --enable-checking --fatal-warnings
|
VALAFLAGS := -g --save-temps --enable-checking --fatal-warnings --vapidir=vapi
|
||||||
|
|
||||||
APPS := geary console syntax lsmbox readmail watchmbox
|
APPS := geary console syntax lsmbox readmail watchmbox
|
||||||
|
|
||||||
|
|
@ -49,7 +49,8 @@ CLIENT_SRC := \
|
||||||
src/client/ui/MainWindow.vala \
|
src/client/ui/MainWindow.vala \
|
||||||
src/client/ui/MessageListView.vala \
|
src/client/ui/MessageListView.vala \
|
||||||
src/client/ui/MessageListStore.vala \
|
src/client/ui/MessageListStore.vala \
|
||||||
src/client/util/Intl.vala
|
src/client/util/Intl.vala \
|
||||||
|
src/client/util/Date.vala
|
||||||
|
|
||||||
CONSOLE_SRC := \
|
CONSOLE_SRC := \
|
||||||
src/console/main.vala
|
src/console/main.vala
|
||||||
|
|
@ -73,7 +74,11 @@ EXTERNAL_PKGS := \
|
||||||
gee-1.0 \
|
gee-1.0 \
|
||||||
gtk+-2.0 \
|
gtk+-2.0 \
|
||||||
unique-1.0 \
|
unique-1.0 \
|
||||||
posix
|
posix \
|
||||||
|
gmime-2.4
|
||||||
|
|
||||||
|
VAPI_FILES := \
|
||||||
|
vapi/gmime-2.4.vapi
|
||||||
|
|
||||||
.PHONY: all
|
.PHONY: all
|
||||||
all: $(APPS)
|
all: $(APPS)
|
||||||
|
|
@ -83,7 +88,7 @@ clean:
|
||||||
rm -f $(ALL_SRC:.vala=.c)
|
rm -f $(ALL_SRC:.vala=.c)
|
||||||
rm -f $(APPS)
|
rm -f $(APPS)
|
||||||
|
|
||||||
geary: $(ENGINE_SRC) $(CLIENT_SRC) Makefile
|
geary: $(ENGINE_SRC) $(CLIENT_SRC) Makefile $(VAPI_FILES)
|
||||||
$(VALAC) $(VALAFLAGS) $(foreach pkg,$(EXTERNAL_PKGS),--pkg=$(pkg)) \
|
$(VALAC) $(VALAFLAGS) $(foreach pkg,$(EXTERNAL_PKGS),--pkg=$(pkg)) \
|
||||||
$(ENGINE_SRC) $(CLIENT_SRC) \
|
$(ENGINE_SRC) $(CLIENT_SRC) \
|
||||||
-o $@
|
-o $@
|
||||||
|
|
|
||||||
|
|
@ -10,22 +10,50 @@ public class MessageListStore : Gtk.TreeStore {
|
||||||
FROM,
|
FROM,
|
||||||
SUBJECT,
|
SUBJECT,
|
||||||
N_COLUMNS;
|
N_COLUMNS;
|
||||||
|
|
||||||
|
public static Column[] all() {
|
||||||
|
return {
|
||||||
|
DATE,
|
||||||
|
FROM,
|
||||||
|
SUBJECT
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Type[] get_types() {
|
||||||
|
return {
|
||||||
|
typeof (string), // DATE
|
||||||
|
typeof (string), // FROM
|
||||||
|
typeof (string) // SUBJECT
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public string to_string() {
|
||||||
|
switch (this) {
|
||||||
|
case DATE:
|
||||||
|
return _("Date");
|
||||||
|
|
||||||
|
case FROM:
|
||||||
|
return _("From");
|
||||||
|
|
||||||
|
case SUBJECT:
|
||||||
|
return _("Subject");
|
||||||
|
|
||||||
|
default:
|
||||||
|
assert_not_reached();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public MessageListStore() {
|
public MessageListStore() {
|
||||||
set_column_types({
|
set_column_types(Column.get_types());
|
||||||
typeof (string), // DATE
|
|
||||||
typeof (string), // FROM
|
|
||||||
typeof (string) // SUBJECT
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void append_message(Geary.Message msg) {
|
public void append_message(Geary.Message msg) {
|
||||||
Gtk.TreeIter iter;
|
Gtk.TreeIter iter;
|
||||||
append(out iter, null);
|
append(out iter, null);
|
||||||
|
|
||||||
set(iter, Column.DATE, msg.sent.value, Column.FROM, msg.from.get_at(0).get_full_address(),
|
set(iter, Column.DATE, Date.pretty_print(msg.sent.value), Column.FROM,
|
||||||
Column.SUBJECT, msg.subject.value);
|
msg.from.get_at(0).get_short_address(), Column.SUBJECT, msg.subject.value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,15 +8,19 @@ public class MessageListView : Gtk.TreeView {
|
||||||
public MessageListView(MessageListStore store) {
|
public MessageListView(MessageListStore store) {
|
||||||
set_model(store);
|
set_model(store);
|
||||||
|
|
||||||
append_column(create_text_column(MessageListStore.Column.DATE, _("Date")));
|
Gtk.CellRendererText date_renderer = new Gtk.CellRendererText();
|
||||||
append_column(create_text_column(MessageListStore.Column.FROM, _("From")));
|
date_renderer.xalign = 1.0f;
|
||||||
append_column(create_text_column(MessageListStore.Column.SUBJECT, _("Subject")));
|
append_column(create_column(MessageListStore.Column.FROM, new Gtk.CellRendererText(),
|
||||||
|
"text", 200));
|
||||||
|
append_column(create_column(MessageListStore.Column.SUBJECT, new Gtk.CellRendererText(),
|
||||||
|
"text", 400));
|
||||||
|
append_column(create_column(MessageListStore.Column.DATE, date_renderer, "text", 100));
|
||||||
}
|
}
|
||||||
|
|
||||||
private Gtk.TreeViewColumn create_text_column(int column, string name, int width = 0,
|
private static Gtk.TreeViewColumn create_column(MessageListStore.Column column,
|
||||||
Gtk.CellRendererText? renderer = null) {
|
Gtk.CellRenderer renderer, string attr, int width = 0) {
|
||||||
Gtk.TreeViewColumn view_column = new Gtk.TreeViewColumn.with_attributes(name,
|
Gtk.TreeViewColumn view_column = new Gtk.TreeViewColumn.with_attributes(column.to_string(),
|
||||||
(renderer != null) ? renderer : new Gtk.CellRendererText(), "text", column);
|
renderer, attr, column);
|
||||||
view_column.set_resizable(true);
|
view_column.set_resizable(true);
|
||||||
|
|
||||||
if (width != 0) {
|
if (width != 0) {
|
||||||
|
|
|
||||||
37
src/client/util/Date.vala
Normal file
37
src/client/util/Date.vala
Normal file
|
|
@ -0,0 +1,37 @@
|
||||||
|
/* Copyright 2011 Yorba Foundation
|
||||||
|
*
|
||||||
|
* This software is licensed under the GNU Lesser General Public License
|
||||||
|
* (version 2.1 or later). See the COPYING file in this distribution.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Date {
|
||||||
|
|
||||||
|
public bool equals(DateTime a, DateTime b) {
|
||||||
|
int year1, month1, day1;
|
||||||
|
a.get_ymd(out year1, out month1, out day1);
|
||||||
|
|
||||||
|
int year2, month2, day2;
|
||||||
|
b.get_ymd(out year2, out month2, out day2);
|
||||||
|
|
||||||
|
return year1 == year2 && month1 == month2 && day1 == day2;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string pretty_print(DateTime datetime) {
|
||||||
|
DateTime now = new DateTime.now_local();
|
||||||
|
string fmt;
|
||||||
|
if (equals(datetime, now)) {
|
||||||
|
// 8:31 am
|
||||||
|
fmt = "%l:%M %P";
|
||||||
|
} else if (datetime.get_year() == now.get_year()) {
|
||||||
|
// Nov 8
|
||||||
|
fmt = "%b %e";
|
||||||
|
} else {
|
||||||
|
// 02/04/10
|
||||||
|
fmt = "%m/%e/%y";
|
||||||
|
}
|
||||||
|
|
||||||
|
return datetime.format(fmt);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -101,8 +101,8 @@ public class Geary.Imap.Flags : Geary.Common.MessageData, Geary.Imap.MessageData
|
||||||
}
|
}
|
||||||
|
|
||||||
public class Geary.Imap.InternalDate : Geary.RFC822.Date, Geary.Imap.MessageData {
|
public class Geary.Imap.InternalDate : Geary.RFC822.Date, Geary.Imap.MessageData {
|
||||||
public InternalDate(string value) {
|
public InternalDate(string iso8601) throws ImapError {
|
||||||
base (value);
|
base (iso8601);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -117,7 +117,8 @@ public class Geary.Imap.EnvelopeDecoder : Geary.Imap.FetchDataDecoder {
|
||||||
StringParameter? in_reply_to = listp.get_as_nullable_string(8);
|
StringParameter? in_reply_to = listp.get_as_nullable_string(8);
|
||||||
StringParameter message_id = listp.get_as_string(9);
|
StringParameter message_id = listp.get_as_string(9);
|
||||||
|
|
||||||
return new Envelope(new Geary.RFC822.Date(sent.value), new Geary.RFC822.Subject(subject.value),
|
return new Envelope(new Geary.RFC822.Date(sent.value),
|
||||||
|
new Geary.RFC822.Subject(subject.value),
|
||||||
parse_addresses(from), parse_addresses(sender), parse_addresses(reply_to),
|
parse_addresses(from), parse_addresses(sender), parse_addresses(reply_to),
|
||||||
(to != null) ? parse_addresses(to) : null,
|
(to != null) ? parse_addresses(to) : null,
|
||||||
(cc != null) ? parse_addresses(cc) : null,
|
(cc != null) ? parse_addresses(cc) : null,
|
||||||
|
|
|
||||||
|
|
@ -62,6 +62,8 @@ public class Geary.Imap.FetchResults {
|
||||||
array += decode_data(data);
|
array += decode_data(data);
|
||||||
} catch (ImapError ierr) {
|
} catch (ImapError ierr) {
|
||||||
// drop bad data on the ground
|
// drop bad data on the ground
|
||||||
|
debug("Dropping FETCH data \"%s\": %s", data.to_string(), ierr.message);
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,14 @@ public class Geary.RFC822.MailboxAddress {
|
||||||
return String.is_empty(name) ? "<%s>".printf(address) : "%s <%s>".printf(name, address);
|
return String.is_empty(name) ? "<%s>".printf(address) : "%s <%s>".printf(name, address);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a human-readable pretty address, showing only the name, but if unavailable, the
|
||||||
|
* mailbox name (that is, the account name without the domain).
|
||||||
|
*/
|
||||||
|
public string get_short_address() {
|
||||||
|
return name ?? mailbox;
|
||||||
|
}
|
||||||
|
|
||||||
public string to_string() {
|
public string to_string() {
|
||||||
return get_full_address();
|
return get_full_address();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -19,9 +19,21 @@ public class Geary.RFC822.MessageID : Geary.Common.StringMessageData, Geary.RFC8
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class Geary.RFC822.Date : Geary.Common.StringMessageData, Geary.RFC822.MessageData {
|
public class Geary.RFC822.Date : Geary.RFC822.MessageData, Geary.Common.MessageData {
|
||||||
public Date(string value) {
|
public string original { get; private set; }
|
||||||
base (value);
|
public DateTime value { get; private set; }
|
||||||
|
|
||||||
|
public Date(string iso8601) throws ImapError {
|
||||||
|
time_t tm = GMime.utils_header_decode_date(iso8601, null);
|
||||||
|
if (tm == 0)
|
||||||
|
throw new ImapError.PARSE_ERROR("Unable to parse \"%s\": not ISO-8601 date", iso8601);
|
||||||
|
|
||||||
|
value = new DateTime.from_unix_utc(tm);
|
||||||
|
original = iso8601;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string to_string() {
|
||||||
|
return original;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
21
vapi/Makefile
Normal file
21
vapi/Makefile
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
# NOTE: The dependencies in this file require vapigen and vala-gen-introspect to be installed,
|
||||||
|
# which are not default in a standard Vala installation.
|
||||||
|
|
||||||
|
GMIME_FILES := \
|
||||||
|
gmime-2.4/gmime-2.4.defines \
|
||||||
|
gmime-2.4/gmime-2.4.files \
|
||||||
|
gmime-2.4/gmime-2.4.metadata \
|
||||||
|
gmime-2.4/gmime-2.4.namespace
|
||||||
|
|
||||||
|
all: gmime-2.4.vapi
|
||||||
|
|
||||||
|
.PHONY: clean
|
||||||
|
clean:
|
||||||
|
rm gmime-2.4.vapi gmime-2.4/gmime-2.4.gi
|
||||||
|
|
||||||
|
gmime-2.4/gmime-2.4.gi: $(GMIME_FILES)
|
||||||
|
vala-gen-introspect gmime-2.4 gmime-2.4
|
||||||
|
|
||||||
|
gmime-2.4.vapi: gmime-2.4/gmime-2.4.gi
|
||||||
|
vapigen --pkg=glib-2.0 --pkg=gio-2.0 --library gmime-2.4 gmime-2.4/gmime-2.4.gi
|
||||||
|
|
||||||
1014
vapi/gmime-2.4.vapi
Normal file
1014
vapi/gmime-2.4.vapi
Normal file
File diff suppressed because it is too large
Load diff
0
vapi/gmime-2.4/gmime-2.4.defines
Normal file
0
vapi/gmime-2.4/gmime-2.4.defines
Normal file
2
vapi/gmime-2.4/gmime-2.4.files
Normal file
2
vapi/gmime-2.4/gmime-2.4.files
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
include/gmime-2.4/
|
||||||
|
lib/libgmime-2.4.so
|
||||||
9
vapi/gmime-2.4/gmime-2.4.metadata
Normal file
9
vapi/gmime-2.4/gmime-2.4.metadata
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
GMime cheader_filename="gmime/gmime.h" lower_case_cprefix="g_mime_"
|
||||||
|
|
||||||
|
g_mime_message_get_date.date is_out="1"
|
||||||
|
g_mime_message_get_date.tz_offset is_out="1"
|
||||||
|
g_mime_param_next name="get_next"
|
||||||
|
g_mime_signer_next name="get_next"
|
||||||
|
|
||||||
|
g_mime_utils_header_decode_date type_name="time_t"
|
||||||
|
g_mime_utils_header_decode_date.tz_offset is_out="1" nullable="1"
|
||||||
1
vapi/gmime-2.4/gmime-2.4.namespace
Normal file
1
vapi/gmime-2.4/gmime-2.4.namespace
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
GMime
|
||||||
Loading…
Add table
Add a link
Reference in a new issue