sw/inc/viewopt.hxx                  |  325 +++++++++++++++++++++++-------------
 sw/source/uibase/config/viewopt.cxx |   25 --
 sw/source/uibase/uno/unotxvw.cxx    |    2 
 3 files changed, 219 insertions(+), 133 deletions(-)

New commits:
commit 8c56abfa64be106c44b2d878968b9b019e126c40
Author:     Tomaž Vajngerl <tomaz.vajng...@collabora.co.uk>
AuthorDate: Thu Oct 27 22:12:35 2022 +0200
Commit:     Tomaž Vajngerl <qui...@gmail.com>
CommitDate: Thu Nov 17 14:54:28 2022 +0100

    sw: convert ViewOptFlags1 from bitflags to struct of bools
    
    Much easier to deal with - let compiler do the bit setting.
    
    Change-Id: I9412e1a2f15e41c9ebf502af57b127c283fc1fa6
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/142214
    Tested-by: Jenkins
    Reviewed-by: Tomaž Vajngerl <qui...@gmail.com>

diff --git a/sw/inc/viewopt.hxx b/sw/inc/viewopt.hxx
index e8a1c299b496..7f65859c341d 100644
--- a/sw/inc/viewopt.hxx
+++ b/sw/inc/viewopt.hxx
@@ -35,42 +35,109 @@ class SwDocShell;
 namespace svtools{ class ColorConfig;}
 enum class SwFillMode;
 
-enum class ViewOptFlags1 : sal_uInt64 {
-    UseHeaderFooterMenu = 0x00000001,
-    Tab           = 0x00000002,
-    Blank         = 0x00000004,
-    HardBlank     = 0x00000008,
-    Paragraph     = 0x00000010,
-    Linebreak     = 0x00000020,
-    Pagebreak     = 0x00000040,
-    Columnbreak   = 0x00000080,
-    SoftHyph      = 0x00000100,
-    Bookmarks     = 0x00000200,
-    Ref           = 0x00000400,
-    FieldName     = 0x00000800,
-    Postits       = 0x00004000,
-    FieldHidden   = 0x00008000,
-    CharHidden    = 0x00010000,
-    Graphic       = 0x00020000,
-    Table         = 0x00040000,
-    Draw          = 0x00080000,
-    Control       = 0x00100000,
-    Crosshair     = 0x00400000,
-    Snap          = 0x00800000,
-    Synchronize   = 0x01000000,
-    GridVisible   = 0x02000000,
-    OnlineSpell   = 0x04000000,
-    TreatSubOutlineLevelsAsContent = 0x08000000,
-    ShowInlineTooltips = 0x10000000, //tooltips on tracked changes
-    ViewMetachars = 0x20000000,
-    Pageback      = 0x40000000,
-    ShowOutlineContentVisibilityButton = 0x80000000,
-    ShowChangesInMargin = 0x100000000, //tracked deletions in margin
-    ShowChangesInMargin2 = 0x200000000 //tracked insertions in margin
+struct ViewOptFlags1
+{
+    bool bUseHeaderFooterMenu : 1;
+    bool bTab : 1;
+    bool bBlank : 1;
+    bool bHardBlank : 1;
+    bool bParagraph : 1;
+    bool bLinebreak : 1;
+    bool bPagebreak : 1;
+    bool bColumnbreak : 1;
+    bool bSoftHyph : 1;
+    bool bBookmarks : 1;
+    bool bRef : 1;
+    bool bFieldName : 1;
+    bool bPostits : 1;
+    bool bFieldHidden : 1;
+    bool bCharHidden : 1;
+    bool bGraphic : 1;
+    bool bTable : 1;
+    bool bDraw : 1;
+    bool bControl : 1;
+    bool bCrosshair : 1;
+    bool bSnap : 1;
+    bool bSynchronize : 1;
+    bool bGridVisible : 1;
+    bool bOnlineSpell : 1;
+    bool bTreatSubOutlineLevelsAsContent : 1;
+    bool bShowInlineTooltips : 1; //tooltips on tracked changes
+    bool bViewMetachars : 1;
+    bool bPageback : 1;
+    bool bShowOutlineContentVisibilityButton : 1;
+    bool bShowChangesInMargin : 1; //tracked deletions in margin
+    bool bShowChangesInMargin2 : 1; //tracked insertions in margin
+
+    ViewOptFlags1()
+        : bUseHeaderFooterMenu(false)
+        , bTab(false)
+        , bBlank(false)
+        , bHardBlank(true)
+        , bParagraph(false)
+        , bLinebreak(false)
+        , bPagebreak(false)
+        , bColumnbreak(false)
+        , bSoftHyph(true)
+        , bBookmarks(false)
+        , bRef(true)
+        , bFieldName(false)
+        , bPostits(true)
+        , bFieldHidden(false)
+        , bCharHidden(false)
+        , bGraphic(true)
+        , bTable(true)
+        , bDraw(true)
+        , bControl(true)
+        , bCrosshair(false)
+        , bSnap(false)
+        , bSynchronize(false)
+        , bGridVisible(false)
+        , bOnlineSpell(false)
+        , bTreatSubOutlineLevelsAsContent(false)
+        , bShowInlineTooltips(false)
+        , bViewMetachars(false)
+        , bPageback(true)
+        , bShowOutlineContentVisibilityButton(false)
+        , bShowChangesInMargin(false)
+        , bShowChangesInMargin2(false)
+    {}
+
+    bool operator==(const ViewOptFlags1& rOther) const
+    {
+        return bUseHeaderFooterMenu == rOther.bUseHeaderFooterMenu
+            && bTab == rOther.bTab
+            && bBlank == rOther.bBlank
+            && bHardBlank == rOther.bHardBlank
+            && bParagraph == rOther.bParagraph
+            && bLinebreak == rOther.bLinebreak
+            && bPagebreak == rOther.bPagebreak
+            && bColumnbreak == rOther.bColumnbreak
+            && bSoftHyph == rOther.bSoftHyph
+            && bBookmarks == rOther.bBookmarks
+            && bRef == rOther.bRef
+            && bFieldName == rOther.bFieldName
+            && bPostits == rOther.bPostits
+            && bFieldHidden == rOther.bFieldHidden
+            && bCharHidden == rOther.bCharHidden
+            && bGraphic == rOther.bGraphic
+            && bTable == rOther.bTable
+            && bDraw == rOther.bDraw
+            && bControl == rOther.bControl
+            && bCrosshair == rOther.bCrosshair
+            && bSnap == rOther.bSnap
+            && bSynchronize == rOther.bSynchronize
+            && bGridVisible == rOther.bGridVisible
+            && bOnlineSpell == rOther.bOnlineSpell
+            && bTreatSubOutlineLevelsAsContent == 
rOther.bTreatSubOutlineLevelsAsContent
+            && bShowInlineTooltips == rOther.bShowInlineTooltips
+            && bViewMetachars == rOther.bViewMetachars
+            && bPageback == rOther.bPageback
+            && bShowOutlineContentVisibilityButton == 
rOther.bShowOutlineContentVisibilityButton
+            && bShowChangesInMargin == rOther.bShowChangesInMargin
+            && bShowChangesInMargin2 == rOther.bShowChangesInMargin2;
+    }
 };
-namespace o3tl {
-    template<> struct typed_flags<ViewOptFlags1> : 
is_typed_flags<ViewOptFlags1, 0x3ffdfcfff> {};
-}
 
 enum class ViewOptCoreFlags2 {
     BlackFont         = 0x0001,
@@ -202,7 +269,6 @@ public:
 
     static void Init(const OutputDevice* pWin);        // Initializing of 
static data.
 
-    ViewOptFlags1   GetCoreOptions() const {return m_nCoreOptions;}
     inline void     SetUIOptions( const SwViewOption& );
 
     // Options from nCoreOptions
@@ -214,71 +280,106 @@ public:
     // in the wrong place here... Also currently there are many const 
modifying casts in the code
     // just to call this function on otherwise const objects. Thus declaring 
it as const now.
     void SetIdle( bool b ) const
-        { m_bIdle = b; }
+    { m_bIdle = b; }
 
     bool IsTab(bool bHard = false) const
-                    {   return !m_bReadonly && (m_nCoreOptions & 
ViewOptFlags1::Tab) &&
-                            ((m_nCoreOptions & 
ViewOptFlags1::ViewMetachars)||bHard); }
+    {
+        return !m_bReadonly && m_nCoreOptions.bTab && 
(m_nCoreOptions.bViewMetachars || bHard);
+    }
     void SetTab( bool b )
-        { SetCoreOption(b, ViewOptFlags1::Tab); }
+    {
+        m_nCoreOptions.bTab = b;
+    }
 
     bool IsBlank(bool bHard = false) const
-                    { return !m_bReadonly && (m_nCoreOptions & 
ViewOptFlags1::Blank) &&
-                            ((m_nCoreOptions & 
ViewOptFlags1::ViewMetachars)||bHard); }
-    void SetBlank( bool b )
-        { SetCoreOption(b, ViewOptFlags1::Blank); }
+    {
+        return !m_bReadonly && m_nCoreOptions.bBlank && 
(m_nCoreOptions.bViewMetachars || bHard);
+    }
+    void SetBlank(bool b)
+    {
+        m_nCoreOptions.bBlank = b;
+    }
 
     bool IsHardBlank() const
-                    { return !m_bReadonly && (m_nCoreOptions & 
ViewOptFlags1::HardBlank); }
+    {
+        return !m_bReadonly && (m_nCoreOptions.bHardBlank);
+    }
     void SetHardBlank( bool b )
-        { SetCoreOption(b, ViewOptFlags1::HardBlank); }
+    {
+        m_nCoreOptions.bHardBlank = b;
+    }
 
     bool IsParagraph(bool bHard = false) const
-                    {   return !m_bReadonly && (m_nCoreOptions & 
ViewOptFlags1::Paragraph) &&
-                            ((m_nCoreOptions & 
ViewOptFlags1::ViewMetachars)||bHard); }
+    {
+        return !m_bReadonly && m_nCoreOptions.bParagraph &&
+                            (m_nCoreOptions.bViewMetachars || bHard);
+    }
     void SetParagraph( bool b )
-        { SetCoreOption(b, ViewOptFlags1::Paragraph); }
+    {
+        m_nCoreOptions.bParagraph = b;
+    }
 
     void SetShowBookmarks(bool const b)
     {
-        SetCoreOption(b, ViewOptFlags1::Bookmarks);
+        m_nCoreOptions.bBookmarks = b;
     }
     bool IsShowBookmarks(bool const bHard = false) const
     {
-        return !m_bReadonly && (m_nCoreOptions & ViewOptFlags1::Bookmarks)
+        return !m_bReadonly && (m_nCoreOptions.bBookmarks)
                 && (bHard || IsFieldShadings());
     }
 
     bool IsLineBreak(bool bHard = false) const
-                    {   return !m_bReadonly && (m_nCoreOptions & 
ViewOptFlags1::Linebreak) &&
-                            ((m_nCoreOptions & 
ViewOptFlags1::ViewMetachars)||bHard); }
+    {
+        return !m_bReadonly && (m_nCoreOptions.bLinebreak) &&
+                            ((m_nCoreOptions.bViewMetachars) || bHard);
+    }
     void SetLineBreak( bool b )
-        { SetCoreOption(b, ViewOptFlags1::Linebreak); }
+    {
+        m_nCoreOptions.bLinebreak = b;
+    }
 
     void SetPageBreak( bool b )
-        { SetCoreOption(b, ViewOptFlags1::Pagebreak); }
+    {
+        m_nCoreOptions.bPagebreak = b;
+    }
 
     void SetColumnBreak( bool b)
-        { SetCoreOption(b, ViewOptFlags1::Columnbreak); }
+    {
+        m_nCoreOptions.bColumnbreak = b;
+    }
 
     bool IsSoftHyph() const
-                    { return !m_bReadonly && (m_nCoreOptions & 
ViewOptFlags1::SoftHyph); }
+    { return !m_bReadonly && (m_nCoreOptions.bSoftHyph); }
+
     void SetSoftHyph( bool b )
-        { SetCoreOption(b, ViewOptFlags1::SoftHyph); }
+    {
+        m_nCoreOptions.bSoftHyph = b;
+    }
+
+    bool IsFieldName() const
+    { return !m_bReadonly && (m_nCoreOptions.bFieldName); }
 
-    bool IsFieldName() const       { return !m_bReadonly && (m_nCoreOptions & 
ViewOptFlags1::FieldName); }
     void SetFieldName( bool b )
-        { SetCoreOption(b, ViewOptFlags1::FieldName); }
+    {
+        m_nCoreOptions.bFieldName = b;
+    }
 
     bool IsPostIts() const
-        { return bool(m_nCoreOptions & ViewOptFlags1::Postits); }
+    {
+        return m_nCoreOptions.bPostits;
+    }
+
     void SetPostIts( bool b )
-        { SetCoreOption(b, ViewOptFlags1::Postits); }
+    {
+        m_nCoreOptions.bPostits = b;
+    }
 
     bool IsResolvedPostIts() const
-        { return bool(m_nUIOptions & ViewOptFlags2::ResolvedPostits); }
+    { return bool(m_nUIOptions & ViewOptFlags2::ResolvedPostits); }
+
     void SetResolvedPostIts( bool b )
-        { SetUIOption(b, ViewOptFlags2::ResolvedPostits); }
+    { SetUIOption(b, ViewOptFlags2::ResolvedPostits); }
 
     static void PaintPostIts( OutputDevice *pOut, const SwRect &rRect,
                               bool bIsScript );
@@ -286,106 +387,119 @@ public:
 
     //show/hide tooltips on tracked changes
     bool IsShowInlineTooltips() const
-        { return bool(m_nCoreOptions & ViewOptFlags1::ShowInlineTooltips); }
+    {
+        return m_nCoreOptions.bShowInlineTooltips;
+    }
+
     void SetShowInlineTooltips( bool b )
-        { SetCoreOption(b, ViewOptFlags1::ShowInlineTooltips); }
+    { m_nCoreOptions.bShowInlineTooltips = b; }
 
     //show/hide tracked deletions in text
     bool IsShowChangesInMargin() const
-        { return bool(m_nCoreOptions & ViewOptFlags1::ShowChangesInMargin); }
+    {
+        return m_nCoreOptions.bShowChangesInMargin;
+    }
+
     void SetShowChangesInMargin( bool b )
-        { SetCoreOption(b, ViewOptFlags1::ShowChangesInMargin); }
+    {
+        m_nCoreOptions.bShowChangesInMargin = b;
+    }
 
     //show/hide tracked insertions in text
     bool IsShowChangesInMargin2() const
-        { return bool(m_nCoreOptions & ViewOptFlags1::ShowChangesInMargin2); }
+    { return m_nCoreOptions.bShowChangesInMargin2; }
+
     void SetShowChangesInMargin2( bool b )
-        { SetCoreOption(b, ViewOptFlags1::ShowChangesInMargin2); }
+    { m_nCoreOptions.bShowChangesInMargin2 = b; }
 
     //show/hide interactive header/footer on top/bottom of pages
     bool IsUseHeaderFooterMenu() const
-        { return bool(m_nCoreOptions & ViewOptFlags1::UseHeaderFooterMenu ); }
+    { return m_nCoreOptions.bUseHeaderFooterMenu; }
     void SetUseHeaderFooterMenu( bool b )
-        { SetCoreOption(b, ViewOptFlags1::UseHeaderFooterMenu); }
+    { m_nCoreOptions.bUseHeaderFooterMenu = b; }
 
     //show/hide outline content visibility button
     bool IsShowOutlineContentVisibilityButton() const;
     void SetShowOutlineContentVisibilityButton(bool b)
-        { SetCoreOption(b, ViewOptFlags1::ShowOutlineContentVisibilityButton); 
}
+    { m_nCoreOptions.bShowOutlineContentVisibilityButton = b; }
 
     bool IsTreatSubOutlineLevelsAsContent() const;
     void SetTreatSubOutlineLevelsAsContent(bool b)
-        { SetCoreOption(b, ViewOptFlags1::TreatSubOutlineLevelsAsContent); }
-
+    { m_nCoreOptions.bTreatSubOutlineLevelsAsContent = b; }
 
     bool IsShowHiddenChar(bool bHard = false) const
-        { return !m_bReadonly && (m_nCoreOptions & ViewOptFlags1::CharHidden) 
&&
-                            ((m_nCoreOptions & 
ViewOptFlags1::ViewMetachars)||bHard); }
+    { return !m_bReadonly && m_nCoreOptions.bCharHidden &&
+                            (m_nCoreOptions.bViewMetachars || bHard); }
 
     void SetShowHiddenChar( bool b )
-        { SetCoreOption(b, ViewOptFlags1::CharHidden); }
+    { m_nCoreOptions.bCharHidden = b; }
 
     bool IsShowHiddenField() const
-        { return !m_bReadonly && (m_nCoreOptions & 
ViewOptFlags1::FieldHidden); }
+    { return !m_bReadonly && m_nCoreOptions.bFieldHidden; }
     void SetShowHiddenField( bool b )
-        { SetCoreOption(b, ViewOptFlags1::FieldHidden); }
+    { m_nCoreOptions.bFieldHidden = b; }
 
     bool IsGraphic() const
-        { return bool(m_nCoreOptions & ViewOptFlags1::Graphic); }
+    { return m_nCoreOptions.bGraphic; }
     void SetGraphic( bool b )
-        { SetCoreOption(b, ViewOptFlags1::Graphic); }
+    { m_nCoreOptions.bGraphic = b; }
 
     bool IsPageBack() const
-        { return bool(m_nCoreOptions & ViewOptFlags1::Pageback); }
+    { return m_nCoreOptions.bPageback; }
     void SetPageBack( bool b )
-        { SetCoreOption(b, ViewOptFlags1::Pageback); }
+    { m_nCoreOptions.bPageback = b; }
 
     bool IsTable() const
-        { return bool(m_nCoreOptions & ViewOptFlags1::Table); }
+    { return m_nCoreOptions.bTable; }
     void SetTable( bool b )
-        { SetCoreOption(b, ViewOptFlags1::Table); }
+    { m_nCoreOptions.bTable = b; }
 
     bool IsDraw() const
-        { return bool(m_nCoreOptions & ViewOptFlags1::Draw); }
+    { return m_nCoreOptions.bDraw; }
     void SetDraw( bool b )
-        { SetCoreOption(b, ViewOptFlags1::Draw); }
+    { m_nCoreOptions.bDraw = b; }
 
     bool IsControl() const
-        { return bool(m_nCoreOptions & ViewOptFlags1::Control); }
+    { return m_nCoreOptions.bControl; }
     void SetControl( bool b )
-        { SetCoreOption(b, ViewOptFlags1::Control); }
+    { m_nCoreOptions.bControl = b; }
 
     bool IsSnap() const
-        { return bool(m_nCoreOptions & ViewOptFlags1::Snap); }
+    { return m_nCoreOptions.bSnap; }
     void SetSnap( bool b )
-        { SetCoreOption(b, ViewOptFlags1::Snap); }
+    { m_nCoreOptions.bSnap = b; }
 
     void SetSnapSize( Size const &rSz ){ m_aSnapSize = rSz; }
     const Size &GetSnapSize() const { return m_aSnapSize; }
 
     bool IsGridVisible() const
-        { return !m_bReadonly && (m_nCoreOptions & 
ViewOptFlags1::GridVisible); }
+    { return !m_bReadonly && m_nCoreOptions.bGridVisible; }
     void SetGridVisible( bool b )
-        { SetCoreOption(b, ViewOptFlags1::GridVisible); }
+    { m_nCoreOptions.bGridVisible = b; }
 
     bool IsOnlineSpell() const
-        { return !m_bReadonly && (m_nCoreOptions & 
ViewOptFlags1::OnlineSpell); }
-    void SetOnlineSpell( bool b );
+    {
+        return !m_bReadonly && m_nCoreOptions.bOnlineSpell;
+    }
+    void SetOnlineSpell( bool b )
+    {
+        m_nCoreOptions.bOnlineSpell = b;
+    }
 
     bool IsViewMetaChars() const
-        { return !m_bReadonly && (m_nCoreOptions & 
ViewOptFlags1::ViewMetachars); }
+    { return !m_bReadonly && m_nCoreOptions.bViewMetachars; }
     void SetViewMetaChars( bool b)
-        { SetCoreOption(b, ViewOptFlags1::ViewMetachars); }
+    { m_nCoreOptions.bViewMetachars = b; }
 
     bool IsSynchronize() const
-        {  return bool(m_nCoreOptions & ViewOptFlags1::Synchronize); }
+    {  return m_nCoreOptions.bSynchronize; }
     void SetSynchronize( bool b )
-        { SetCoreOption(b, ViewOptFlags1::Synchronize); }
+    { m_nCoreOptions.bSynchronize = b; }
 
     bool IsCrossHair() const
-        { return bool(m_nCoreOptions & ViewOptFlags1::Crosshair); }
+    { return m_nCoreOptions.bCrosshair; }
     void SetCrossHair( bool b )
-        { SetCoreOption(b, ViewOptFlags1::Crosshair); }
+    { m_nCoreOptions.bCrosshair = b; }
 
     // Options from nCore2Options
     bool IsBlackFont() const
@@ -433,13 +547,6 @@ public:
         else
             m_nCore2Options &= ~f;
     }
-    void SetCoreOption(bool b, ViewOptFlags1 f)
-    {
-        if (b)
-            m_nCoreOptions |= f;
-        else
-            m_nCoreOptions &= ~f;
-    }
 
     short GetDivisionX() const   { return m_nDivisionX; }
     void  SetDivisionX( short n ){ m_nDivisionX = n; }
diff --git a/sw/source/uibase/config/viewopt.cxx 
b/sw/source/uibase/config/viewopt.cxx
index c5e6f3e56b9e..54bbe0636274 100644
--- a/sw/source/uibase/config/viewopt.cxx
+++ b/sw/source/uibase/config/viewopt.cxx
@@ -98,12 +98,12 @@ bool SwViewOption::IsEqualFlags( const SwViewOption &rOpt ) 
const
 
 bool SwViewOption::IsShowOutlineContentVisibilityButton() const
 {
-    return static_cast<bool>(m_nCoreOptions & 
ViewOptFlags1::ShowOutlineContentVisibilityButton);
+    return m_nCoreOptions.bShowOutlineContentVisibilityButton;
 }
 
 bool SwViewOption::IsTreatSubOutlineLevelsAsContent() const
 {
-    return static_cast<bool>(m_nCoreOptions & 
ViewOptFlags1::TreatSubOutlineLevelsAsContent);
+    return m_nCoreOptions.bTreatSubOutlineLevelsAsContent;
 }
 
 void SwViewOption::DrawRect( OutputDevice *pOut,
@@ -178,19 +178,6 @@ SwViewOption::SwViewOption() :
     m_eZoom( SvxZoomType::PERCENT ),
     m_nTableDestination(TBL_DEST_CELL)
 {
-    // Initialisation is a little simpler now
-    // all Bits to 0
-    m_nCoreOptions =
-        ViewOptFlags1::HardBlank |
-        ViewOptFlags1::SoftHyph |
-        ViewOptFlags1::Ref |
-        ViewOptFlags1::Graphic |
-        ViewOptFlags1::Table |
-        ViewOptFlags1::Draw |
-        ViewOptFlags1::Control |
-        ViewOptFlags1::Pageback |
-        ViewOptFlags1::Postits;
-
     m_nCore2Options =
         ViewOptCoreFlags2::BlackFont |
         ViewOptCoreFlags2::HiddenPara;
@@ -334,14 +321,6 @@ bool SwViewOption::IsAutoCompleteWords()
     return rFlags.bAutoCmpltCollectWords;
 }
 
-void SwViewOption::SetOnlineSpell(bool b)
-{
-    if (b)
-        m_nCoreOptions |= ViewOptFlags1::OnlineSpell;
-    else
-        m_nCoreOptions &= ~ViewOptFlags1::OnlineSpell;
-}
-
 AuthorCharAttr::AuthorCharAttr() :
     m_nItemId (SID_ATTR_CHAR_UNDERLINE),
     m_nAttr   (LINESTYLE_SINGLE),
diff --git a/sw/source/uibase/uno/unotxvw.cxx b/sw/source/uibase/uno/unotxvw.cxx
index 65401a8410e6..8b82e83285e8 100644
--- a/sw/source/uibase/uno/unotxvw.cxx
+++ b/sw/source/uibase/uno/unotxvw.cxx
@@ -812,7 +812,7 @@ uno::Any SAL_CALL SwXTextView::getPropertyValue(
             const SwViewOption *pOpt = m_pView->GetWrtShell().GetViewOptions();
             if (!pOpt)
                 throw RuntimeException();
-            aRet <<= bool(pOpt->GetCoreOptions() & ViewOptFlags1::OnlineSpell);
+            aRet <<= pOpt->IsOnlineSpell();
         }
         break;
         default :

Reply via email to