1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3  * License, v. 2.0. If a copy of the MPL was not distributed with this
4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 
6 #include "nsMsgTxn.h"
7 #include "nsIMsgHdr.h"
8 #include "nsIMsgDatabase.h"
9 #include "nsCOMArray.h"
10 #include "nsArrayEnumerator.h"
11 #include "nsComponentManagerUtils.h"
12 #include "nsVariant.h"
13 #include "nsIProperty.h"
14 #include "nsMsgMessageFlags.h"
15 #include "nsIMsgFolder.h"
16 
17 NS_IMPL_ADDREF(nsMsgTxn)
NS_IMPL_RELEASE(nsMsgTxn)18 NS_IMPL_RELEASE(nsMsgTxn)
19 NS_INTERFACE_MAP_BEGIN(nsMsgTxn)
20   NS_INTERFACE_MAP_ENTRY(nsIWritablePropertyBag)
21   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsIPropertyBag, nsIWritablePropertyBag)
22   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIWritablePropertyBag)
23   NS_INTERFACE_MAP_ENTRY(nsITransaction)
24   NS_INTERFACE_MAP_ENTRY(nsIPropertyBag2)
25   NS_INTERFACE_MAP_ENTRY(nsIWritablePropertyBag2)
26 NS_INTERFACE_MAP_END
27 
28 nsMsgTxn::nsMsgTxn() { m_txnType = 0; }
29 
~nsMsgTxn()30 nsMsgTxn::~nsMsgTxn() {}
31 
Init()32 nsresult nsMsgTxn::Init() { return NS_OK; }
33 
HasKey(const nsAString & name,bool * aResult)34 NS_IMETHODIMP nsMsgTxn::HasKey(const nsAString& name, bool* aResult) {
35   *aResult = mPropertyHash.Get(name, nullptr);
36   return NS_OK;
37 }
38 
Get(const nsAString & name,nsIVariant ** _retval)39 NS_IMETHODIMP nsMsgTxn::Get(const nsAString& name, nsIVariant** _retval) {
40   mPropertyHash.Get(name, _retval);
41   return NS_OK;
42 }
43 
GetProperty(const nsAString & name,nsIVariant ** _retval)44 NS_IMETHODIMP nsMsgTxn::GetProperty(const nsAString& name,
45                                     nsIVariant** _retval) {
46   return mPropertyHash.Get(name, _retval) ? NS_OK : NS_ERROR_FAILURE;
47 }
48 
SetProperty(const nsAString & name,nsIVariant * value)49 NS_IMETHODIMP nsMsgTxn::SetProperty(const nsAString& name, nsIVariant* value) {
50   NS_ENSURE_ARG_POINTER(value);
51   mPropertyHash.InsertOrUpdate(name, value);
52   return NS_OK;
53 }
54 
DeleteProperty(const nsAString & name)55 NS_IMETHODIMP nsMsgTxn::DeleteProperty(const nsAString& name) {
56   if (!mPropertyHash.Get(name, nullptr)) return NS_ERROR_FAILURE;
57 
58   mPropertyHash.Remove(name);
59   return mPropertyHash.Get(name, nullptr) ? NS_ERROR_FAILURE : NS_OK;
60 }
61 
62 //
63 // nsMailSimpleProperty class and impl; used for GetEnumerator
64 // This is same as nsSimpleProperty but for external API use.
65 //
66 
67 class nsMailSimpleProperty final : public nsIProperty {
68  public:
nsMailSimpleProperty(const nsAString & aName,nsIVariant * aValue)69   nsMailSimpleProperty(const nsAString& aName, nsIVariant* aValue)
70       : mName(aName), mValue(aValue) {}
71 
72   NS_DECL_ISUPPORTS
73   NS_DECL_NSIPROPERTY
74  protected:
~nsMailSimpleProperty()75   ~nsMailSimpleProperty() {}
76 
77   nsString mName;
78   nsCOMPtr<nsIVariant> mValue;
79 };
80 
NS_IMPL_ISUPPORTS(nsMailSimpleProperty,nsIProperty)81 NS_IMPL_ISUPPORTS(nsMailSimpleProperty, nsIProperty)
82 
83 NS_IMETHODIMP nsMailSimpleProperty::GetName(nsAString& aName) {
84   aName.Assign(mName);
85   return NS_OK;
86 }
87 
GetValue(nsIVariant ** aValue)88 NS_IMETHODIMP nsMailSimpleProperty::GetValue(nsIVariant** aValue) {
89   NS_IF_ADDREF(*aValue = mValue);
90   return NS_OK;
91 }
92 
93 // end nsMailSimpleProperty
94 
GetEnumerator(nsISimpleEnumerator ** _retval)95 NS_IMETHODIMP nsMsgTxn::GetEnumerator(nsISimpleEnumerator** _retval) {
96   nsCOMArray<nsIProperty> propertyArray;
97   for (auto iter = mPropertyHash.Iter(); !iter.Done(); iter.Next()) {
98     nsMailSimpleProperty* sprop =
99         new nsMailSimpleProperty(iter.Key(), iter.Data());
100     propertyArray.AppendObject(sprop);
101   }
102   return NS_NewArrayEnumerator(_retval, propertyArray, NS_GET_IID(nsIProperty));
103 }
104 
105 #define IMPL_GETSETPROPERTY_AS(Name, Type)                              \
106   NS_IMETHODIMP                                                         \
107   nsMsgTxn::GetPropertyAs##Name(const nsAString& prop, Type* _retval) { \
108     nsIVariant* v = mPropertyHash.GetWeak(prop);                        \
109     if (!v) return NS_ERROR_NOT_AVAILABLE;                              \
110     return v->GetAs##Name(_retval);                                     \
111   }                                                                     \
112                                                                         \
113   NS_IMETHODIMP                                                         \
114   nsMsgTxn::SetPropertyAs##Name(const nsAString& prop, Type value) {    \
115     nsCOMPtr<nsIWritableVariant> var = new nsVariant();                 \
116     var->SetAs##Name(value);                                            \
117     return SetProperty(prop, var);                                      \
118   }
119 
IMPL_GETSETPROPERTY_AS(Int32,int32_t)120 IMPL_GETSETPROPERTY_AS(Int32, int32_t)
121 IMPL_GETSETPROPERTY_AS(Uint32, uint32_t)
122 IMPL_GETSETPROPERTY_AS(Int64, int64_t)
123 IMPL_GETSETPROPERTY_AS(Uint64, uint64_t)
124 IMPL_GETSETPROPERTY_AS(Double, double)
125 IMPL_GETSETPROPERTY_AS(Bool, bool)
126 
127 NS_IMETHODIMP nsMsgTxn::GetPropertyAsAString(const nsAString& prop,
128                                              nsAString& _retval) {
129   nsIVariant* v = mPropertyHash.GetWeak(prop);
130   if (!v) return NS_ERROR_NOT_AVAILABLE;
131   return v->GetAsAString(_retval);
132 }
133 
GetPropertyAsACString(const nsAString & prop,nsACString & _retval)134 NS_IMETHODIMP nsMsgTxn::GetPropertyAsACString(const nsAString& prop,
135                                               nsACString& _retval) {
136   nsIVariant* v = mPropertyHash.GetWeak(prop);
137   if (!v) return NS_ERROR_NOT_AVAILABLE;
138   return v->GetAsACString(_retval);
139 }
140 
GetPropertyAsAUTF8String(const nsAString & prop,nsACString & _retval)141 NS_IMETHODIMP nsMsgTxn::GetPropertyAsAUTF8String(const nsAString& prop,
142                                                  nsACString& _retval) {
143   nsIVariant* v = mPropertyHash.GetWeak(prop);
144   if (!v) return NS_ERROR_NOT_AVAILABLE;
145   return v->GetAsAUTF8String(_retval);
146 }
147 
GetPropertyAsInterface(const nsAString & prop,const nsIID & aIID,void ** _retval)148 NS_IMETHODIMP nsMsgTxn::GetPropertyAsInterface(const nsAString& prop,
149                                                const nsIID& aIID,
150                                                void** _retval) {
151   nsIVariant* v = mPropertyHash.GetWeak(prop);
152   if (!v) return NS_ERROR_NOT_AVAILABLE;
153   nsCOMPtr<nsISupports> val;
154   nsresult rv = v->GetAsISupports(getter_AddRefs(val));
155   if (NS_FAILED(rv)) return rv;
156   if (!val) {
157     // We have a value, but it's null
158     *_retval = nullptr;
159     return NS_OK;
160   }
161   return val->QueryInterface(aIID, _retval);
162 }
163 
SetPropertyAsAString(const nsAString & prop,const nsAString & value)164 NS_IMETHODIMP nsMsgTxn::SetPropertyAsAString(const nsAString& prop,
165                                              const nsAString& value) {
166   nsCOMPtr<nsIWritableVariant> var = new nsVariant();
167   var->SetAsAString(value);
168   return SetProperty(prop, var);
169 }
170 
SetPropertyAsACString(const nsAString & prop,const nsACString & value)171 NS_IMETHODIMP nsMsgTxn::SetPropertyAsACString(const nsAString& prop,
172                                               const nsACString& value) {
173   nsCOMPtr<nsIWritableVariant> var = new nsVariant();
174   var->SetAsACString(value);
175   return SetProperty(prop, var);
176 }
177 
SetPropertyAsAUTF8String(const nsAString & prop,const nsACString & value)178 NS_IMETHODIMP nsMsgTxn::SetPropertyAsAUTF8String(const nsAString& prop,
179                                                  const nsACString& value) {
180   nsCOMPtr<nsIWritableVariant> var = new nsVariant();
181   var->SetAsAUTF8String(value);
182   return SetProperty(prop, var);
183 }
184 
SetPropertyAsInterface(const nsAString & prop,nsISupports * value)185 NS_IMETHODIMP nsMsgTxn::SetPropertyAsInterface(const nsAString& prop,
186                                                nsISupports* value) {
187   nsCOMPtr<nsIWritableVariant> var = new nsVariant();
188   var->SetAsISupports(value);
189   return SetProperty(prop, var);
190 }
191 
192 /////////////////////// Transaction Stuff //////////////////
DoTransaction(void)193 NS_IMETHODIMP nsMsgTxn::DoTransaction(void) { return NS_OK; }
194 
GetIsTransient(bool * aIsTransient)195 NS_IMETHODIMP nsMsgTxn::GetIsTransient(bool* aIsTransient) {
196   if (nullptr != aIsTransient)
197     *aIsTransient = false;
198   else
199     return NS_ERROR_NULL_POINTER;
200   return NS_OK;
201 }
202 
Merge(nsITransaction * aTransaction,bool * aDidMerge)203 NS_IMETHODIMP nsMsgTxn::Merge(nsITransaction* aTransaction, bool* aDidMerge) {
204   *aDidMerge = false;
205   return NS_OK;
206 }
207 
GetMsgWindow(nsIMsgWindow ** msgWindow)208 nsresult nsMsgTxn::GetMsgWindow(nsIMsgWindow** msgWindow) {
209   if (!msgWindow || !m_msgWindow) return NS_ERROR_NULL_POINTER;
210   NS_ADDREF(*msgWindow = m_msgWindow);
211   return NS_OK;
212 }
213 
SetMsgWindow(nsIMsgWindow * msgWindow)214 nsresult nsMsgTxn::SetMsgWindow(nsIMsgWindow* msgWindow) {
215   m_msgWindow = msgWindow;
216   return NS_OK;
217 }
218 
SetTransactionType(uint32_t txnType)219 nsresult nsMsgTxn::SetTransactionType(uint32_t txnType) {
220   return SetPropertyAsUint32(u"type"_ns, txnType);
221 }
222 
223 /*none of the callers pass null aFolder,
224   we always initialize aResult (before we pass in) for the case where the key is
225   not in the db*/
CheckForToggleDelete(nsIMsgFolder * aFolder,const nsMsgKey & aMsgKey,bool * aResult)226 nsresult nsMsgTxn::CheckForToggleDelete(nsIMsgFolder* aFolder,
227                                         const nsMsgKey& aMsgKey,
228                                         bool* aResult) {
229   NS_ENSURE_ARG(aResult);
230   nsCOMPtr<nsIMsgDBHdr> message;
231   nsCOMPtr<nsIMsgDatabase> db;
232   nsresult rv = aFolder->GetMsgDatabase(getter_AddRefs(db));
233   if (db) {
234     bool containsKey;
235     rv = db->ContainsKey(aMsgKey, &containsKey);
236     if (NS_FAILED(rv) || !containsKey)  // the message has been deleted from db,
237                                         // so we cannot do toggle here
238       return NS_OK;
239     rv = db->GetMsgHdrForKey(aMsgKey, getter_AddRefs(message));
240     uint32_t flags;
241     if (NS_SUCCEEDED(rv) && message) {
242       message->GetFlags(&flags);
243       *aResult = (flags & nsMsgMessageFlags::IMAPDeleted) != 0;
244     }
245   }
246   return rv;
247 }
248