end
 
   if $opts[:search]
-    SearchResultsMode.spawn_from_query $opts[:search]
+    SearchResultsMode.spawn_from_query $opts[:search], true
   end
 
   until Redwood::exceptions.nonempty? || $die
     when :search
       query = BufferManager.ask :search, "search all messages: "
       next unless query && query !~ /^\s*$/
-      SearchResultsMode.spawn_from_query query
+      SearchResultsMode.spawn_from_query query, true
     when :search_unread
-      SearchResultsMode.spawn_from_query "is:unread"
+      SearchResultsMode.spawn_from_query "is:unread", InboxMode.newest_first
     when :list_labels
       labels = LabelManager.all_labels.map { |l| LabelManager.string_for l }
       user_label = bm.ask_with_completions :label, "Show threads with label (enter for listing): ", labels
 
     k.add :refine_search, "Refine search", '|'
   end
 
+  def self.newest_first
+    if !$config[:inbox_newest_first].nil?
+      $config[:inbox_newest_first]
+    else
+      true
+    end
+  end
+
   def initialize
     super [:inbox, :sent, :draft], { :label => :inbox, :skip_killed => true }
     raise "can't have more than one!" if defined? @@instance
     @@instance = self
+    @newest_first = InboxMode.newest_first
   end
 
   def is_relevant? m; (m.labels & [:spam, :deleted, :killed, :inbox]) == Set.new([:inbox]) end
   def refine_search
     text = BufferManager.ask :search, "refine query: ", "label:inbox AND "
     return unless text && text !~ /^\s*$/
-    SearchResultsMode.spawn_from_query text
+    SearchResultsMode.spawn_from_query text, @newest_first
   end
 
   ## label-list-mode wants to be able to raise us if the user selects
 
 module Redwood
 
 class LabelSearchResultsMode < ThreadIndexMode
-  def initialize labels
+  def initialize labels, newest_first
     @labels = labels
     opts = { :labels => @labels }
     opts[:load_deleted] = true if labels.include? :deleted
     opts[:load_spam] = true if labels.include? :spam
     super [], opts
+    @newest_first = newest_first
   end
 
   register_keymap do |k|
     label_query = @labels.size > 1 ? "(#{@labels.join('||')})" : @labels.first
     query = BufferManager.ask :search, "refine query: ", "+label:#{label_query} "
     return unless query && query !~ /^\s*$/
-    SearchResultsMode.spawn_from_query query
+    SearchResultsMode.spawn_from_query query, @newest_first
   end
 
   def is_relevant? m; @labels.all? { |l| m.has_label? l } end
     when :inbox
       BufferManager.raise_to_front InboxMode.instance.buffer
     else
-      b, new = BufferManager.spawn_unless_exists("All threads with label '#{label}'") { LabelSearchResultsMode.new [label] }
+      b, new = BufferManager.spawn_unless_exists("All threads with label '#{label}'") { LabelSearchResultsMode.new [label], true }
       b.mode.load_threads :num => b.content_height if new
     end
   end
 
 module Redwood
 
 class SearchResultsMode < ThreadIndexMode
-  def initialize query
+  def initialize query, newest_first
     @query = query
     super [], query
+    @newest_first = newest_first
   end
 
   register_keymap do |k|
   def refine_search
     text = BufferManager.ask :search, "refine query: ", (@query[:text] + " ")
     return unless text && text !~ /^\s*$/
-    SearchResultsMode.spawn_from_query text
+    SearchResultsMode.spawn_from_query text, @newest_first
   end
 
   ## a proper is_relevant? method requires some way of asking ferret
   ## the message, and search against it to see if i have > 0 results,
   ## but that seems pretty insane.
 
-  def self.spawn_from_query text
+  def self.spawn_from_query text, newest_first
     begin
       query = Index.parse_query(text)
       return unless query
       short_text = text.length < 20 ? text : text[0 ... 20] + "..."
-      mode = SearchResultsMode.new query
+      mode = SearchResultsMode.new query, newest_first
       BufferManager.spawn "search: \"#{short_text}\"", mode
       mode.load_threads :num => mode.buffer.content_height
     rescue Index::ParseError => e
 
     k.add :tag_matching, "Tag matching threads", 'g'
     k.add :apply_to_tagged, "Apply next command to all tagged threads", '+', '='
     k.add :join_threads, "Force tagged threads to be joined into the same thread", '#'
+    k.add :toggle_sort, "Toggle newest first/last sort order", 'o'
     k.add :undo, "Undo the previous action", 'u'
   end
 
     @hidden_labels = hidden_labels + LabelManager::HIDDEN_RESERVED_LABELS
     @date_width = DATE_WIDTH
 
+    @newest_first = true
+
     @interrupt_search = false
     
     initialize_threads # defines @ts and @ts_mutex
     UndoManager.undo
   end
 
+  def toggle_sort
+    @newest_first = !@newest_first
+    update
+  end
+
   def update
     @mutex.synchronize do
       ## let's see you do THIS in python
-      @threads = @ts.threads.select { |t| !@hidden_threads[t] }.sort_by { |t| [t.date, t.first.id] }.reverse
+      @threads = @ts.threads.select { |t| !@hidden_threads[t] }.sort_by { |t| [t.date, t.first.id] }
+      if @newest_first
+        @threads = @threads.reverse
+      end
       @size_widgets = @threads.map { |t| size_widget_for_thread t }
       @size_widget_width = @size_widgets.max_of { |w| w.display_length }
     end
     else
       n = opts[:num]
     end
+    if !@newest_first
+      n = -1
+    end
 
     myopts = @load_thread_opts.merge({ :when_done => (lambda do |num|
       opts[:when_done].call(num) if opts[:when_done]