Revision: 7204
          http://svn.sourceforge.net/mahogany/?rev=7204&view=rev
Author:   vadz
Date:     2007-01-08 13:23:41 -0800 (Mon, 08 Jan 2007)

Log Message:
-----------
Refactoring, fixes and improvements to addresses expansion:

- extract the non-GUI login into functions in AdbManager.h/.cpp
- extract GUI logic for addresses in wxTextCtrl (and wxComboBox in the future)
  in separate AddressExpander class
- better/more consistent handling of to:/cc:/... prefixes
- expand all addresses and not just the 1st one when Enter is pressed (bug 921)

Modified Paths:
--------------
    trunk/M/M.vcproj
    trunk/M/include/Composer.h
    trunk/M/include/adb/AdbManager.h
    trunk/M/include/gui/wxComposeView.h
    trunk/M/src/adb/AdbManager.cpp
    trunk/M/src/classes/MApplication.cpp
    trunk/M/src/gui/wxComposeView.cpp
    trunk/M/src/mail/MailFolder.cpp

Added Paths:
-----------
    trunk/M/include/gui/AddressExpander.h
    trunk/M/src/gui/AddressExpander.cpp

Modified: trunk/M/M.vcproj
===================================================================
--- trunk/M/M.vcproj    2007-01-08 00:09:32 UTC (rev 7203)
+++ trunk/M/M.vcproj    2007-01-08 21:23:41 UTC (rev 7204)
@@ -373,6 +373,9 @@
                                Name="gui"
                                Filter="">
                                <File
+                                       
RelativePath=".\src\gui\AddressExpander.cpp">
+                               </File>
+                               <File
                                        RelativePath=".\src\gui\ClickAtt.cpp">
                                </File>
                                <File
@@ -859,7 +862,8 @@
                                                <Tool
                                                        Name="VCCustomBuildTool"
                                                        Description="Creating 
MInterface.h and .cpp"
-                                                       
CommandLine="extra\scripts\m4.bat $(InputDir) $(InputDir)"
+                                                       
CommandLine="extra\scripts\m4.bat $(InputDir) $(InputDir)
+"
                                                        
AdditionalDependencies="$(InputDir)/MInterface.mid;$(InputDir)/MInterface.cpp.m4;$(InputDir)/MInterface.h.m4;$(InputDir)/mid2cpp.m4;$(InputDir)/mid2h.m4"
                                                        
Outputs="$(InputDir)/MInterface.cpp;$(InputDir)/MInterface.h"/>
                                        </FileConfiguration>
@@ -868,7 +872,8 @@
                                                <Tool
                                                        Name="VCCustomBuildTool"
                                                        Description="Creating 
MInterface.h and .cpp"
-                                                       
CommandLine="extra\scripts\m4.bat $(InputDir) $(InputDir)"
+                                                       
CommandLine="extra\scripts\m4.bat $(InputDir) $(InputDir)
+"
                                                        
AdditionalDependencies="$(InputDir)/MInterface.mid;$(InputDir)/MInterface.cpp.m4;$(InputDir)/MInterface.h.m4;$(InputDir)/mid2cpp.m4;$(InputDir)/mid2h.m4"
                                                        
Outputs="$(InputDir)/MInterface.cpp;$(InputDir)/MInterface.h"/>
                                        </FileConfiguration>
@@ -877,7 +882,8 @@
                                                <Tool
                                                        Name="VCCustomBuildTool"
                                                        Description="Creating 
MInterface.h and .cpp"
-                                                       
CommandLine="extra\scripts\m4.bat $(InputDir) $(InputDir)"
+                                                       
CommandLine="extra\scripts\m4.bat $(InputDir) $(InputDir)
+"
                                                        
AdditionalDependencies="$(InputDir)/MInterface.mid;$(InputDir)/MInterface.cpp.m4;$(InputDir)/MInterface.h.m4;$(InputDir)/mid2cpp.m4;$(InputDir)/mid2h.m4"
                                                        
Outputs="$(InputDir)/MInterface.cpp;$(InputDir)/MInterface.h"/>
                                        </FileConfiguration>
@@ -886,7 +892,8 @@
                                                <Tool
                                                        Name="VCCustomBuildTool"
                                                        Description="Creating 
MInterface.h and .cpp"
-                                                       
CommandLine="extra\scripts\m4.bat $(InputDir) $(InputDir)"
+                                                       
CommandLine="extra\scripts\m4.bat $(InputDir) $(InputDir)
+"
                                                        
AdditionalDependencies="$(InputDir)/MInterface.mid;$(InputDir)/MInterface.cpp.m4;$(InputDir)/MInterface.h.m4;$(InputDir)/mid2cpp.m4;$(InputDir)/mid2h.m4"
                                                        
Outputs="$(InputDir)/MInterface.cpp;$(InputDir)/MInterface.h"/>
                                        </FileConfiguration>
@@ -1880,6 +1887,9 @@
                                RelativePath=".\include\AddressCC.h">
                        </File>
                        <File
+                               RelativePath=".\include\gui\AddressExpander.h">
+                       </File>
+                       <File
                                RelativePath=".\include\ASMailFolder.h">
                        </File>
                        <File

Modified: trunk/M/include/Composer.h
===================================================================
--- trunk/M/include/Composer.h  2007-01-08 00:09:32 UTC (rev 7203)
+++ trunk/M/include/Composer.h  2007-01-08 21:23:41 UTC (rev 7204)
@@ -56,6 +56,13 @@
 class Composer
 {
 public:
+   /// Flags for AddRecipients()
+   enum
+   {
+      /// Expand the address before adding it
+      AddRcpt_Expand = 1
+   };
+
    /**
       @name Different ways to create a new composer window
 
@@ -186,7 +193,7 @@
    /// adds recipients from addr (Recipient_Max means to reuse the last)
    virtual void AddRecipients(const String& addr,
                               RecipientType rcptType = Recipient_Max,
-                              bool doLayout = true) = 0;
+                              int flags = AddRcpt_Expand) = 0;
 
    /// adds a "To" recipient
    void AddTo(const String& addr) { AddRecipients(addr, Recipient_To); }
@@ -223,15 +230,6 @@
    */
    virtual void AddHeaderEntry(const String& entry, const String& value) = 0;
 
-   /**
-      Expand the given string: this method handles address book completion and
-      mailto: URLs parsing. It modifies the string passed to it in place.
-
-      @param text the text to expand, modified by the method
-      @return the inferred recipient type or Recipient_None if invalid address
-   */
-   virtual RecipientType ExpandRecipient(String *text) = 0;
-
    //@}
 
    /** @name Add/insert stuff into composer */

Modified: trunk/M/include/adb/AdbManager.h
===================================================================
--- trunk/M/include/adb/AdbManager.h    2007-01-08 00:09:32 UTC (rev 7203)
+++ trunk/M/include/adb/AdbManager.h    2007-01-08 21:23:41 UTC (rev 7204)
@@ -17,6 +17,8 @@
 
 #include "adb/AdbEntry.h"   // for AdbLookup_xxx constants
 
+#include "RecipientType.h"
+
 #ifndef USE_PCH
 #  include <wx/dynarray.h>
 #endif // USE_PCH
@@ -25,6 +27,8 @@
 class AdbBook;
 class AdbDataProvider;
 
+class WXDLLEXPORT wxFrame;
+
 // arrays
 WX_DEFINE_ARRAY(AdbBook *, ArrayAdbBooks);
 WX_DEFINE_ARRAY(AdbEntryGroup *, ArrayAdbGroups);
@@ -186,10 +190,70 @@
 
   @return FALSE if no matches, TRUE if at least one item matched
 */
-class wxFrame;
 extern bool AdbExpand(wxArrayString& results,
                       const String& what,
                       int how,
                       wxFrame *frame);
 
+/**
+   Expand a single address coming from the user input.
+
+   The user input can be a full address, a mailto: URL or a string to be
+   expanded using AdbExpand().
+
+   This function doesn't support multiple comma-separated addresses, use
+   AdbExpandRecipients() for this. Nor does it support "cc:"-like
+   prefixes selecting the recipient type, as AdbExpandSingleRecipient() does.
+
+   @param address the address string, modified in place by this function
+   @param subject filled with the subject on output if it's specified as
+                  part of the address (currently only happens with mailto)
+                  and is left empty otherwise
+   @param profile to use for expansion options
+   @param parent window to use as parent for the dialogs
+   @return true if the address was expanded, false if the expansion was
+           cancelled (address is unchanged then)
+ */
+bool AdbExpandSingleAddress(String *address,
+                            String *subject,
+                            Profile *profile,
+                            wxFrame *win);
+
+/**
+   Expand a single address coming from the user input, possibly with a
+   recipient type string.
+
+   This function does the same thing as AdbExpandSingleAddress() except that
+   accepts "to:", "cc:" &c prefixes.
+
+   Returns the recipient type (which can be Recipient_None if none was
+   explicitly specified) or Recipient_Max is expansion was cancelled and the
+   address is unchanged.
+ */
+RecipientType AdbExpandSingleRecipient(String *address,
+                                       String *subject,
+                                       Profile *profile,
+                                       wxFrame *win);
+
+/**
+   Expand all addresses in the specified string.
+
+   Returns the number of addresses which can be 0 if the control was empty
+   or -1 if the expansion was cancelled.
+
+   @param text contains the addresses to expand
+   @param addresses filled in with the addresses on return
+   @param rcptTypes filled in with RecipientType enum elements
+   @param subject filled with the subject on output
+   @param profile to use for expansion options
+   @param parent window to use as parent for the dialogs
+   @return number of addresses expanded or -1 if cancelled
+ */
+int AdbExpandAllRecipients(const String& text,
+                           wxArrayString& addresses,
+                           wxArrayInt& rcptTypes,
+                           String *subject,
+                           Profile *profile,
+                           wxFrame *win);
+
 #endif  //_ADBMANAGER_H

Added: trunk/M/include/gui/AddressExpander.h
===================================================================
--- trunk/M/include/gui/AddressExpander.h                               (rev 0)
+++ trunk/M/include/gui/AddressExpander.h       2007-01-08 21:23:41 UTC (rev 
7204)
@@ -0,0 +1,73 @@
+///////////////////////////////////////////////////////////////////////////////
+// Project:     M - cross platform e-mail GUI client
+// File name:   gui/AddressExpander.h
+// Purpose:     declaration of AddressExpander class
+// Author:      Vadim Zeitlin
+// Created:     2007-01-08
+// CVS-ID:      $Id$
+// Copyright:   (c) 1998-2007 Mahogany team
+// Licence:     M license
+///////////////////////////////////////////////////////////////////////////////
+
+/**
+   @file gui/AddressExpander.h
+   @brief Declaration of AddressExpander helper.
+
+   AddressExpander can be used with any control which needs to expand email
+   addresses entered into it by user by looking them up in the address books.
+ */
+
+#ifndef _M_GUI_ADDRESSEXPANDER_H_
+#define _M_GUI_ADDRESSEXPANDER_H_
+
+#include "RecipientType.h"
+
+class WXDLLEXPORT wxFrame;
+class WXDLLEXPORT wxTextCtrl;
+
+/**
+   AddressExpander is not a control but can be associated with an existing
+   control to add support for expanding addresses in it.
+ */
+class AddressExpander
+{
+public:
+   /**
+      Create an AddressExpander associated with the given text entry zone.
+
+      @param text the associated text control
+      @param profile for expansion options
+    */
+   AddressExpander(wxTextCtrl *text, Profile *profile);
+
+   /**
+      Calls AdbExpandAllRecipients() for the control contents.
+
+      Doesn't modify the control contents.
+    */
+   int ExpandAll(wxArrayString& addresses,
+                 wxArrayInt& rcptTypes,
+                 String *subject) const;
+
+   /**
+      Replaces the last address entered into the control with its expansion.
+
+      @param subject filled in with the subject if the recipient contains it
+      @return type of the recipient if explicitly specified, Recipient_None if
+              none and Recipient_Max if nothing was expanded
+    */
+   RecipientType ExpandLast(String *subject);
+
+private:
+   // return the parent window for ADB functions
+   wxFrame *GetParentFrame() const;
+
+
+   wxTextCtrl *m_text;
+   Profile_obj m_profile;
+
+   DECLARE_NO_COPY_CLASS(AddressExpander)
+};
+
+#endif // _M_GUI_ADDRESSEXPANDER_H_
+

Modified: trunk/M/include/gui/wxComposeView.h
===================================================================
--- trunk/M/include/gui/wxComposeView.h 2007-01-08 00:09:32 UTC (rev 7203)
+++ trunk/M/include/gui/wxComposeView.h 2007-01-08 21:23:41 UTC (rev 7204)
@@ -169,14 +169,11 @@
    /// sets Subject field
    void SetSubject(const String &subj);
 
-   /// adds recepients from addr (Recepient_Max means to reuse the last)
+   /// adds recipients from addr (Recipient_Max means to reuse the last)
    virtual void AddRecipients(const String& addr,
                               RecipientType rcptType = Recipient_Max,
-                              bool doLayout = true);
+                              int flags = AddRcpt_Expand);
 
-   /// expands an address
-   virtual RecipientType ExpandRecipient(String *text);
-
    /// get from value (empty means default)
    String GetFrom() const;
 

Modified: trunk/M/src/adb/AdbManager.cpp
===================================================================
--- trunk/M/src/adb/AdbManager.cpp      2007-01-08 00:09:32 UTC (rev 7203)
+++ trunk/M/src/adb/AdbManager.cpp      2007-01-08 21:23:41 UTC (rev 7204)
@@ -39,6 +39,12 @@
 #include "adb/AdbDialogs.h"
 
 // ----------------------------------------------------------------------------
+// options we use here
+// ----------------------------------------------------------------------------
+
+extern const MOption MP_ADB_SUBSTRINGEXPANSION;
+
+// ----------------------------------------------------------------------------
 // types
 // ----------------------------------------------------------------------------
 
@@ -339,6 +345,204 @@
   return !results.IsEmpty();
 }
 
+bool
+AdbExpandSingleAddress(String *address,
+                       String *subject,
+                       Profile *profile,
+                       wxFrame *win)
+{
+   CHECK( address && subject, false, "NULL input address" );
+
+   subject->clear();
+
+   String textOrig = *address;
+
+   // remove "mailto:"; prefix if it's there - this is convenient when you paste
+   // in an URL from the web browser
+   //
+   // TODO: add support for the mailto URL parameters, i.e. should support
+   //       things like "mailto:[EMAIL PROTECTED]"
+   String newText;
+   if ( !textOrig.StartsWith(_T("mailto:";), &newText) )
+   {
+      // if the text already has a '@' inside it and looks like a full email
+      // address assume that it doesn't need to be expanded (this saves a lot
+      // of time as expanding a non existing address looks through all address
+      // books...)
+      size_t pos = textOrig.find('@');
+      if ( pos != String::npos && pos > 0 && pos < textOrig.length() )
+      {
+         // also check that the host part of the address is expanded - it
+         // should contain at least one dot normally
+         if ( wxStrchr(textOrig.c_str() + pos + 1, '.') )
+         {
+            // looks like a valid address - nothing to do
+            newText = textOrig;
+         }
+      }
+
+      if ( newText.empty() )
+      {
+         wxArrayString expansions;
+
+         if ( !AdbExpand(expansions,
+                         textOrig,
+                         READ_CONFIG(profile, MP_ADB_SUBSTRINGEXPANSION)
+                           ? AdbLookup_Substring
+                           : AdbLookup_StartsWith,
+                         win) )
+         {
+            // cancelled, indicate it by returning invalid recipient type
+            return false;
+         }
+
+         // construct the replacement string(s)
+         size_t nExpCount = expansions.GetCount();
+         for ( size_t nExp = 0; nExp < nExpCount; nExp++ )
+         {
+            if ( nExp > 0 )
+               newText += ", ";
+
+            newText += expansions[nExp];
+         }
+      }
+   }
+   //else: address following mailto: doesn't need to be expanded
+
+   *address = newText;
+
+   return true;
+}
+
+RecipientType
+AdbExpandSingleRecipient(String *address,
+                         String *subject,
+                         Profile *profile,
+                         wxFrame *win)
+{
+   CHECK( address, Recipient_Max, "NULL input address" );
+
+   String text = *address;
+   RecipientType rcptType = Recipient_None;
+   if ( text.length() > 3 )
+   {
+      // check for to:, cc: or bcc: prefix
+      if ( text[2u] == ':' )
+      {
+         if ( toupper(text[0u]) == 'T' && toupper(text[1u]) == 'O' )
+            rcptType = Recipient_To;
+         else if ( toupper(text[0u]) == 'C' && toupper(text[1u]) == 'C' )
+            rcptType = Recipient_Cc;
+      }
+      else if ( text[3u] == ':' && text(0, 3).Upper() == _T("BCC") )
+      {
+         rcptType = Recipient_Bcc;
+      }
+
+      if ( rcptType != Recipient_None )
+      {
+         // erase the prefix (length 2 or 3) with the colon
+         text.erase(0, rcptType == Recipient_Bcc ? 4 : 3);
+      }
+   }
+
+   if ( !AdbExpandSingleAddress(&text, subject, profile, win) )
+     return Recipient_Max;
+
+   *address = text;
+
+   return rcptType;
+}
+
+int
+AdbExpandAllRecipients(const String& text,
+                       wxArrayString& addresses,
+                       wxArrayInt& rcptTypes,
+                       String *subject,
+                       Profile *profile,
+                       wxFrame *win)
+{
+   addresses.clear();
+   rcptTypes.clear();
+
+   int count = 0;
+   bool expandedSomething = false; // will be set to true if expand any address
+
+   // expand all addresses, one by one
+   const size_t len = text.length();
+   String address;
+   address.reserve(len);
+   bool quoted = false;
+   for ( size_t n = 0; n <= len; n++ )
+   {
+      switch ( const wxChar ch = n == len ? '\0' : text[n] )
+      {
+         case '"':
+            quoted = !quoted;
+            break;
+
+         case '\\':
+            // backslash escapes the next character (if there is one), so
+            // append it without special handling, even if it's a quote or
+            // address separator
+            if ( n < len - 1 )
+               address += text[++n];
+            else
+               wxLogWarning(_("Trailing backslash ignored."));
+            break;
+
+         case ' ':
+            // skip leading spaces unless they're quoted (note that we don't
+            // ignore trailing spaces because we want "Dan " to expand into
+            // "Dan Black" but not into "Danish guy")
+            if ( quoted || !address.empty() )
+               address += ch;
+            break;
+
+         case '\0':
+            if ( quoted )
+            {
+               wxLogWarning(_("Closing open quote implicitly."));
+               quoted = false;
+            }
+            // fall through
+
+         case ',':
+         case ';':
+            if ( !quoted )
+            {
+               // end of this address component, expand and remember it
+               RecipientType rcptType =
+                 AdbExpandSingleRecipient(&address, subject, profile, win);
+               if ( rcptType != Recipient_Max )
+               {
+                  expandedSomething = true;
+               }
+               else // expansion of this address failed
+               {
+                  // still continue with the other ones but don't set
+                  // expandedSomething so that our caller will know if we
+                  // didn't do anything at all
+                  rcptType = Recipient_None;
+               }
+
+               addresses.push_back(address);
+               rcptTypes.push_back(rcptType);
+               count++;
+               address.clear();
+               break;
+            }
+            //else: quoted address separators are not special, fall through
+
+         default:
+            // just accumulate in the current address
+            address += ch;
+      }
+   }
+
+   return expandedSomething ? count : -1;
+}
+
 // ----------------------------------------------------------------------------
 // AdbManager static functions and variables
 // ----------------------------------------------------------------------------

Modified: trunk/M/src/classes/MApplication.cpp
===================================================================
--- trunk/M/src/classes/MApplication.cpp        2007-01-08 00:09:32 UTC (rev 
7203)
+++ trunk/M/src/classes/MApplication.cpp        2007-01-08 21:23:41 UTC (rev 
7204)
@@ -231,20 +231,17 @@
 
    if ( composer )
    {
+      composer->AddRecipients(cmdLineOpts.composer.to, Recipient_To);
       composer->AddRecipients(cmdLineOpts.composer.bcc, Recipient_Bcc);
       composer->AddRecipients(cmdLineOpts.composer.cc, Recipient_Cc);
       composer->AddRecipients(cmdLineOpts.composer.newsgroups,
                               Recipient_Newsgroup);
 
-      // the "to" parameter may be a mailto: URL, pass it through our expansion
-      // function first
-      String to = cmdLineOpts.composer.to;
-      composer->ExpandRecipient(&to);
+      if ( !cmdLineOpts.composer.subject.empty() )
+         composer->SetSubject(cmdLineOpts.composer.subject);
+      //else: don't override the subject which could have been specified as
+      //      part of "To:" recipient (common for mailto: URLs)
 
-      composer->AddRecipients(to, Recipient_To);
-
-      composer->SetSubject(cmdLineOpts.composer.subject);
-
       composer->InsertText(cmdLineOpts.composer.body);
       composer->ResetDirty();
 

Added: trunk/M/src/gui/AddressExpander.cpp
===================================================================
--- trunk/M/src/gui/AddressExpander.cpp                         (rev 0)
+++ trunk/M/src/gui/AddressExpander.cpp 2007-01-08 21:23:41 UTC (rev 7204)
@@ -0,0 +1,125 @@
+///////////////////////////////////////////////////////////////////////////////
+// Project:     M - cross platform e-mail GUI client
+// File name:   gui/AddressExpander.cpp
+// Purpose:     AddressExpander implementation
+// Author:      Vadim Zeitlin
+// Created:     2007-01-08
+// CVS-ID:      $Id: wxComposeView.cpp 7203 2007-01-08 00:09:32Z vadz $
+// Copyright:   (c) 1998-2007 Mahogany team
+// Licence:     M license
+///////////////////////////////////////////////////////////////////////////////
+
+// ============================================================================
+// declarations
+// ============================================================================
+
+// ----------------------------------------------------------------------------
+// headers
+// ----------------------------------------------------------------------------
+
+#include "Mpch.h"
+
+#ifndef USE_PCH
+#  include "Mcommon.h"
+#endif
+
+#include "adb/AdbManager.h"
+
+#include "gui/AddressExpander.h"
+
+// ============================================================================
+// AddressExpander implementation
+// ============================================================================
+
+AddressExpander::AddressExpander(wxTextCtrl *text, Profile *profile)
+               : m_profile(profile)
+{
+   SafeIncRef(profile);
+
+   m_text = text;
+
+   // TODO: connect to TAB and Enter events to handle them automatically?
+}
+
+wxFrame *AddressExpander::GetParentFrame() const
+{
+   return (wxFrame *)wxGetTopLevelParent(m_text);
+}
+
+int
+AddressExpander::ExpandAll(wxArrayString& addresses,
+                           wxArrayInt& rcptTypes,
+                           String *subject) const
+{
+   return AdbExpandAllRecipients
+          (
+            m_text->GetValue(),
+            addresses,
+            rcptTypes,
+            subject,
+            m_profile,
+            GetParentFrame()
+          );
+}
+
+RecipientType AddressExpander::ExpandLast(String *subject)
+{
+   // find the last address
+   String text = m_text->GetValue();
+   const size_t len = text.length();
+   size_t start = 0;
+   bool quoted = false;
+   for ( size_t n = 0; n < len; n++ )
+   {
+      switch ( text[n] )
+      {
+         case '\\':
+            // skip the next character, even if it's a quote or separator
+            n++;
+            break;
+
+         case '"':
+            quoted = !quoted;
+            break;
+
+         case ',':
+         case ';':
+            if ( !quoted )
+            {
+               // keep the space if there is one following the separator
+               if ( n < len - 1 && text[n + 1] == ' ' )
+                  n++;
+
+               start = n;
+            }
+            break;
+      }
+   }
+
+   // if we didn't find the final quote, skip over the initial one too
+   if ( quoted )
+      start++;
+
+   if ( start == len )
+      return Recipient_Max; // nothing to expand
+
+   // preserve the part before the address start
+   String textBefore;
+   start++;
+   textBefore.assign(text, 0, start);
+   text.erase(0, start);
+   text.Trim(false /* from left */);
+
+   // expand the address
+   RecipientType rcptType =
+      AdbExpandSingleRecipient(&text, subject, m_profile, GetParentFrame());
+
+   if ( rcptType != Recipient_Max )
+   {
+      m_text->SetValue(textBefore + text);
+      m_text->SetInsertionPointEnd();
+   }
+
+   return rcptType;
+}
+

Modified: trunk/M/src/gui/wxComposeView.cpp
===================================================================
--- trunk/M/src/gui/wxComposeView.cpp   2007-01-08 00:09:32 UTC (rev 7203)
+++ trunk/M/src/gui/wxComposeView.cpp   2007-01-08 21:23:41 UTC (rev 7204)
@@ -86,6 +86,7 @@
 
 #include "HeadersDialogs.h"
 
+#include "gui/AddressExpander.h"
 #include "gui/wxIdentityCombo.h"
 #include "gui/wxOptionsDlg.h"
 #include "gui/wxDialogLayout.h"
@@ -581,7 +582,8 @@
 // different roles rather than because it is really needed.
 // ----------------------------------------------------------------------------
 
-class wxAddressTextCtrl : public wxTextCtrlProcessingEnter
+class wxAddressTextCtrl : public wxTextCtrlProcessingEnter,
+                          public AddressExpander
 {
 public:
    // ctor
@@ -1217,16 +1219,34 @@
 void wxRcptMainControl::OnAdd()
 {
    // expand before adding (make this optional?)
-   RecipientType addrType = GetText()->DoExpand();
-   if ( addrType == Recipient_None )
+   wxArrayString addresses;
+   wxArrayInt rcptTypes;
+   String subject;
+   const int count = GetText()->ExpandAll(addresses, rcptTypes, &subject);
+   if ( count == -1 )
    {
-      // cancelled or address is invalid
+      // cancelled by user
       return;
    }
 
-   // add new recipient(s)
-   m_composeView->AddRecipients(GetText()->GetValue(), addrType);
+   if ( !subject.empty() )
+      m_composeView->SetSubject(subject);
 
+   for ( unsigned n = 0; n < (unsigned)count; n++ )
+   {
+      // add new recipient(s)
+      RecipientType rcptType = (RecipientType)rcptTypes[n];
+      if ( rcptType == Recipient_None )
+      {
+         // use the default one
+         rcptType = GetType();
+      }
+
+      // don't [try to] expand the address again here
+      m_composeView->AddRecipients(addresses[n], rcptType,
+                                   !Composer::AddRcpt_Expand);
+   }
+
    // clear the entry zone as recipient(s) were moved elsewhere
    GetText()->SetValue(wxEmptyString);
 }
@@ -1320,7 +1340,9 @@
 
 wxAddressTextCtrl::wxAddressTextCtrl(wxWindow *parent,
                                      wxRcptControl *rcptControl)
-                 : wxTextCtrlProcessingEnter(parent, wxTE_PROCESS_TAB)
+                 : wxTextCtrlProcessingEnter(parent, wxTE_PROCESS_TAB),
+                   AddressExpander(this,
+                                     rcptControl->GetComposer()->GetProfile())
 {
    m_rcptControl = rcptControl;
 }
@@ -1377,15 +1399,11 @@
       case Recipient_Cc:
       case Recipient_Bcc:
          {
-            String text = GetValue();
+            String subject;
+            rcptType = ExpandLast(&subject);
 
-            rcptType = GetComposer()->ExpandRecipient(&text);
-
-            if ( rcptType != Recipient_None )
-            {
-               SetValue(text);
-               SetInsertionPointEnd();
-            }
+            if ( !subject.empty() )
+               m_rcptControl->GetComposer()->SetSubject(subject);
          }
          break;
 
@@ -2301,198 +2319,6 @@
 // wxComposeView address headers stuff
 // ----------------------------------------------------------------------------
 
-RecipientType
-wxComposeView::ExpandRecipient(String *textAddress)
-{
-   // don't do anything for the newsgroups
-   //
-   // TODO-NEWS: expand using .newsrc?
-   if ( m_mode == wxComposeView::Mode_News )
-   {
-      return Recipient_Newsgroup;
-   }
-
-   // try to expand the last component
-   String& text = *textAddress;
-
-   // trim spaces from left, but not (all) from right -- this allows "Dan " to
-   // be expanded into "Dan Black" but not in "Danish Guy"
-   text.Trim(FALSE);
-   bool hasSpaceAtEnd = !text.empty() && text.Last() == ' ';
-   text.Trim(TRUE);
-   if ( !text.empty() && hasSpaceAtEnd )
-      text += ' ';
-
-   // check for the lone '"' simplifies the code for finding the starting
-   // position below: it should be done here, otherwise the following loop
-   // will crash!
-   if ( text.empty() || text == '"' )
-   {
-      // don't do anything
-      wxLogStatus(GetFrame(),
-                  _("Nothing to expand - please enter something."));
-
-      return Recipient_None;
-   }
-
-   // find the starting position of the last address in the address list
-   size_t nLastAddr;
-   bool quoted = text.Last() == '"';
-   if ( quoted )
-   {
-      // just find the matching quote (not escaped)
-      const wxChar *pStart = text.c_str();
-      const wxChar *p;
-      for ( p = pStart + text.length() - 2; p >= pStart; p-- )
-      {
-         if ( *p == '"' )
-         {
-            // check that it's not escaped
-            if ( (p == pStart) || (*(p - 1) != '\\') )
-            {
-               // ok, found it!
-               break;
-            }
-         }
-      }
-
-      nLastAddr = p - pStart;
-   }
-   else // unquoted
-   {
-      // search back until the last address separator
-      for ( nLastAddr = text.length() - 1; nLastAddr > 0; nLastAddr-- )
-      {
-         wxChar c = text[nLastAddr];
-         if ( (c == ',') || (c == ';') )
-            break;
-      }
-
-      if ( nLastAddr > 0 )
-      {
-         // move beyond the ',' or ';' which stopped the scan
-         nLastAddr++;
-      }
-
-      // the address will probably never start with spaces but if it does, it
-      // will be enough to just take it into quotes
-      while ( wxIsspace(text[nLastAddr]) )
-      {
-         nLastAddr++;
-      }
-   }
-
-   // so now we've got the text we'll be trying to expand
-   String textOrig = text.c_str() + nLastAddr;
-
-   // do we have an explicit address type specifier
-   RecipientType addrType = Recipient_Max;
-   if ( textOrig.length() > 3 )
-   {
-      // check for to:, cc: or bcc: prefix
-      if ( textOrig[2u] == ':' )
-      {
-         if ( toupper(textOrig[0u]) == 'T' && toupper(textOrig[1u]) == 'O' )
-            addrType = Recipient_To;
-         else if ( toupper(textOrig[0u]) == 'C' && toupper(textOrig[1u]) == 
'C' )
-            addrType = Recipient_Cc;
-      }
-      else if ( textOrig[3u] == ':' && textOrig(0, 3).Upper() == _T("BCC") )
-      {
-         addrType = Recipient_Bcc;
-      }
-
-      if ( addrType != Recipient_Max )
-      {
-         // erase the colon as well
-         textOrig.erase(0, addrType == Recipient_Bcc ? 4 : 3);
-      }
-   }
-
-   // remove "mailto:"; prefix if it's there - this is convenient when you paste
-   // in an URL from the web browser
-   //
-   // TODO: add support for the mailto URL parameters, i.e. should support
-   //       things like "mailto:[EMAIL PROTECTED]"
-   String newText;
-   if ( !textOrig.StartsWith(_T("mailto:";), &newText) )
-   {
-      // if the text already has a '@' inside it and looks like a full email
-      // address assume that it doesn't need to be expanded (this saves a lot
-      // of time as expanding a non existing address looks through all address
-      // books...)
-      size_t pos = textOrig.find('@');
-      if ( pos != String::npos && pos > 0 && pos < textOrig.length() )
-      {
-         // also check that the host part of the address is expanded - it
-         // should contain at least one dot normally
-         if ( wxStrchr(textOrig.c_str() + pos + 1, '.') )
-         {
-            // looks like a valid address - nothing to do
-            newText = textOrig;
-         }
-      }
-
-      if ( newText.empty() )
-      {
-         wxArrayString expansions;
-
-         if ( !AdbExpand(expansions,
-                         textOrig,
-                         READ_CONFIG(GetProfile(), MP_ADB_SUBSTRINGEXPANSION)
-                           ? AdbLookup_Substring
-                           : AdbLookup_StartsWith,
-                         this) )
-         {
-            // cancelled, don't do anything
-            return Recipient_None;
-         }
-
-         // construct the replacement string(s)
-         size_t nExpCount = expansions.GetCount();
-         for ( size_t nExp = 0; nExp < nExpCount; nExp++ )
-         {
-            if ( nExp > 0 )
-               newText += CANONIC_ADDRESS_SEPARATOR;
-
-            newText += expansions[nExp];
-         }
-      }
-   }
-
-   // find the end of the previous address
-   size_t nPrevAddrEnd;
-   if ( nLastAddr > 0 )
-   {
-      // undo "++" above
-      nLastAddr--;
-   }
-
-   for ( nPrevAddrEnd = nLastAddr; nPrevAddrEnd > 0; nPrevAddrEnd-- )
-   {
-      wxChar c = text[nPrevAddrEnd];
-      if ( !wxIsspace(c) && (c != ',') && (c != ';') )
-      {
-         // this character is a part of previous string, leave it there
-         nPrevAddrEnd++;
-
-         break;
-      }
-   }
-
-   // keep the text up to the address we expanded/processed
-   wxString oldText(text, nPrevAddrEnd);  // first nPrevAddrEnd chars
-   if ( !oldText.empty() )
-   {
-      // there was something before, add separator
-      oldText += CANONIC_ADDRESS_SEPARATOR;
-   }
-
-   text = oldText + newText;
-
-   return addrType;
-}
-
 void
 wxComposeView::AddRecipientControls(const String& value, RecipientType rt)
 {
@@ -2569,12 +2395,16 @@
 }
 
 void
-wxComposeView::AddRecipients(const String& address, RecipientType addrType, 
bool doLayout)
+wxComposeView::AddRecipients(const String& addressOrig,
+                             RecipientType addrType,
+                             int flags)
 {
    // if there is no address, nothing to do
-   if ( address.empty() )
+   if ( addressOrig.empty() )
       return;
 
+   String address = addressOrig;
+
    // invalid rcpt type means to reuse the last one
    if ( addrType == Recipient_Max )
    {
@@ -2605,6 +2435,15 @@
       case Recipient_To:
       case Recipient_Cc:
       case Recipient_Bcc:
+         if ( flags & AddRcpt_Expand )
+         {
+            String subject;
+            AdbExpandSingleAddress(&address, &subject, GetProfile(), this);
+
+            if ( !subject.empty() )
+               SetSubject(subject);
+         }
+
          // an email address
          {
             // split the string in addreses and add all of them

Modified: trunk/M/src/mail/MailFolder.cpp
===================================================================
--- trunk/M/src/mail/MailFolder.cpp     2007-01-08 00:09:32 UTC (rev 7203)
+++ trunk/M/src/mail/MailFolder.cpp     2007-01-08 21:23:41 UTC (rev 7204)
@@ -680,7 +680,7 @@
 
       while ( n-- )
       {
-         cv->AddRecipients(rcptAddresses[n], (RecipientType)rcptTypes[n], (n > 
0 ? false : true));
+         cv->AddRecipients(rcptAddresses[n], (RecipientType)rcptTypes[n]);
       }
 
       return;
@@ -869,7 +869,7 @@
 
    while ( n-- )
    {
-      cv->AddRecipients(rcptAddresses[n], (RecipientType)rcptTypes[n], !n);
+      cv->AddRecipients(rcptAddresses[n], (RecipientType)rcptTypes[n]);
    }
 }
 


This was sent by the SourceForge.net collaborative development platform, the 
world's largest Open Source development site.

-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your
opinions on IT & business topics through brief surveys - and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV
_______________________________________________
Mahogany-cvsupdates mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/mahogany-cvsupdates

Reply via email to