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