Neuron®
The Neuron® is the basis for the creation of open and secure federated networks for smart societies.
Loading...
Searching...
No Matches
MailClient.cs
1using System;
2using System.Collections.Generic;
3using System.Text;
4using System.Threading.Tasks;
5using System.Xml;
9using Waher.Events;
11
13{
18 {
22 public const string NamespaceMail = "urn:xmpp:smtp";
23
29 : base(Client)
30 {
31 Client.RegisterMessageHandler("mailInfo", NamespaceMail, this.MailHandler, true);
32 }
33
35 public override void Dispose()
36 {
37 this.Client.UnregisterMessageHandler("mailInfo", NamespaceMail, this.MailHandler, true);
38
39 base.Dispose();
40 }
41
45 public override string[] Extensions => new string[] { };
46
47 private Task MailHandler(object Sender, MessageEventArgs e)
48 {
49 string ContentType = XML.Attribute(e.Content, "contentType");
50 string MessageId = XML.Attribute(e.Content, "id");
51 int Priority = XML.Attribute(e.Content, "priority", 3);
52 DateTimeOffset Date = XML.Attribute(e.Content, "date", DateTimeOffset.Now);
53 string FromMail = XML.Attribute(e.Content, "fromMail");
54 string FromHeader = XML.Attribute(e.Content, "fromHeader");
55 string Sender2 = XML.Attribute(e.Content, "sender");
56 int Size = XML.Attribute(e.Content, "size", 0);
57 string MailObjectId = XML.Attribute(e.Content, "cid");
58 List<KeyValuePair<string, string>> Headers = new List<KeyValuePair<string, string>>();
59 List<EmbeddedObjectReference> Attachments = null;
60 List<EmbeddedObjectReference> Inline = null;
61
62 foreach (XmlNode N in e.Content.ChildNodes)
63 {
64 if (N is XmlElement E)
65 {
66 switch (E.LocalName)
67 {
68 case "headers":
69 foreach (XmlNode N2 in E.ChildNodes)
70 {
71 switch (N2.LocalName)
72 {
73 case "header":
74 string Key = XML.Attribute((XmlElement)N2, "name");
75 string Value = N2.InnerText;
76
77 Headers.Add(new KeyValuePair<string, string>(Key, Value));
78 break;
79 }
80 }
81 break;
82
83 case "attachment":
84 case "inline":
85 string ContentType2 = XML.Attribute(E, "contentType");
86 string Description = XML.Attribute(E, "description");
87 string FileName = XML.Attribute(E, "fileName");
88 string Name = XML.Attribute(E, "name");
89 string ContentId = XML.Attribute(E, "id");
90 string EmbeddedObjectId = XML.Attribute(E, "cid");
91 int Size2 = XML.Attribute(E, "size", 0);
92
93 EmbeddedObjectReference Ref = new EmbeddedObjectReference(ContentType2, Description, FileName, Name,
94 ContentId, EmbeddedObjectId, Size);
95
96 if (E.LocalName == "inline")
97 {
98 if (Inline is null)
99 Inline = new List<EmbeddedObjectReference>();
100
101 Inline.Add(Ref);
102 }
103 else
104 {
105 if (Attachments is null)
106 Attachments = new List<EmbeddedObjectReference>();
107
108 Attachments.Add(Ref);
109 }
110 break;
111 }
112 }
113 }
114
115 string PlainText = e.Body;
116 string Html = null;
117 string Markdown = null;
118
119 foreach (XmlNode N in e.Message.ChildNodes)
120 {
121 if (N is XmlElement E)
122 {
123 switch (E.LocalName)
124 {
125 case "content":
126 if (E.NamespaceURI == "urn:xmpp:content")
127 {
128 switch (XML.Attribute(E, "type").ToLower())
129 {
131 PlainText = E.InnerText;
132 break;
133
134 case "text/html":
135 Html = E.InnerText;
136 break;
137
138 case "text/markdown":
139 Markdown = E.InnerText;
140 break;
141 }
142 }
143 break;
144
145 case "html":
146 if (E.NamespaceURI == "http://jabber.org/protocol/xhtml-im")
147 {
148 foreach (XmlNode N2 in E.ChildNodes)
149 {
150 if (N2 is XmlElement E2 && E2.LocalName == "body")
151 {
152 Html = E2.OuterXml; // InnerXml introduces xmlns attributes on all child elements.
153
154 int i = Html.IndexOf('>');
155 Html = Html.Substring(i + 1);
156
157 i = Html.LastIndexOf('<');
158 Html = Html.Substring(0, i);
159 break;
160 }
161 }
162 }
163 break;
164 }
165 }
166 }
167
168 return this.MailReceived.Raise(this, new MailEventArgs(this, e, ContentType, MessageId, (Priority)Priority,
169 Date, FromMail, FromHeader, Sender2, Size, MailObjectId, Headers.ToArray(), Attachments?.ToArray(),
170 Inline?.ToArray(), PlainText, Html, Markdown));
171 }
172
176 public event EventHandlerAsync<MailEventArgs> MailReceived = null;
177
184 public Task Get(string ObjectId, EventHandlerAsync<MessageObjectEventArgs> Callback, object State)
185 {
186 return this.Get(ObjectId, string.Empty, Callback, State);
187 }
188
196 public Task Get(string ObjectId, string ContentType, EventHandlerAsync<MessageObjectEventArgs> Callback, object State)
197 {
198 StringBuilder Xml = new StringBuilder();
199
200 Xml.Append("<get xmlns='");
201 Xml.Append(NamespaceMail);
202 Xml.Append("' cid='");
203 Xml.Append(XML.Encode(ObjectId));
204
205 if (!string.IsNullOrEmpty(ContentType))
206 {
207 Xml.Append("' type='");
208 Xml.Append(XML.Encode(ContentType));
209 }
210
211 Xml.Append("'/>");
212
213 return this.client.SendIqGet(this.client.Domain, Xml.ToString(), async (Sender, e) =>
214 {
215 XmlElement E;
216 string ResponseContentType = null;
217 byte[] Data = null;
218
219 if (e.Ok && !((E = e.FirstElement) is null) && E.LocalName == "content" && E.NamespaceURI == NamespaceMail)
220 {
221 try
222 {
223 ResponseContentType = XML.Attribute(E, "type");
224 Data = Convert.FromBase64String(E.InnerText);
225 }
226 catch (Exception)
227 {
228 e.Ok = false;
229 }
230 }
231 else
232 e.Ok = false;
233
234 await Callback.Raise(this, new MessageObjectEventArgs(e, ResponseContentType, Data));
235 }, State);
236 }
237
242 public Task<MessageObject> GetAsync(string ObjectId)
243 {
244 return this.GetAsync(ObjectId, string.Empty);
245 }
246
252 public async Task<MessageObject> GetAsync(string ObjectId, string ContentType)
253 {
254 TaskCompletionSource<MessageObject> Result = new TaskCompletionSource<MessageObject>();
255
256 await this.Get(ObjectId, ContentType, (Sender, e) =>
257 {
258 if (e.Ok)
259 Result.TrySetResult(new MessageObject(e.Data, e.ContentType));
260 else
261 Result.TrySetException(e.StanzaError ?? new Exception("Unable to get message object."));
262
263 return Task.CompletedTask;
264
265 }, null);
266
267 return await Result.Task;
268 }
269
276 public Task Delete(string ObjectId, EventHandlerAsync<IqResultEventArgs> Callback, object State)
277 {
278 return this.client.SendIqSet(this.client.Domain, "<delete xmlns='" + NamespaceMail + "' cid='" + XML.Encode(ObjectId) + "'/>",
279 Callback, State);
280 }
281
286 public async Task DeleteAsync(string ObjectId)
287 {
288 TaskCompletionSource<bool> Result = new TaskCompletionSource<bool>();
289
290 await this.Delete(ObjectId, (Sender, e) =>
291 {
292 if (e.Ok)
293 Result.TrySetResult(true);
294 else
295 Result.TrySetException(e.StanzaError ?? new Exception("Unable to delete message object."));
296
297 return Task.CompletedTask;
298
299 }, null);
300
301 await Result.Task;
302 }
303
315 public Task AppendContent(string ContentId, string ContentType, byte[] ContentData, ContentDisposition Disposition,
316 string Name, string FileName, string Description, StringBuilder Xml)
317 {
318 Xml.Append("<content xmlns='");
319 Xml.Append(NamespaceMail);
320 Xml.Append("' cid='");
321 Xml.Append(XML.Encode(ContentId));
322 Xml.Append("' type='");
323 Xml.Append(XML.Encode(ContentType));
324
325 if (Disposition != ContentDisposition.Unknown)
326 {
327 Xml.Append("' disposition='");
328 Xml.Append(XML.Encode(Disposition.ToString()));
329 }
330
331 if (!string.IsNullOrEmpty(Name))
332 {
333 Xml.Append("' name='");
334 Xml.Append(XML.Encode(Name));
335 }
336
337 if (!string.IsNullOrEmpty(FileName))
338 {
339 Xml.Append("' fileName='");
340 Xml.Append(XML.Encode(FileName));
341 }
342
343 if (!string.IsNullOrEmpty(Description))
344 {
345 Xml.Append("' description='");
346 Xml.Append(XML.Encode(Description));
347 }
348
349 Xml.Append("'>");
350 Xml.Append(Convert.ToBase64String(ContentData)); // TODO: Chunked transfer
351 Xml.Append("</content>");
352
353 return Task.CompletedTask;
354 }
355
356 }
357}
Plain text encoder/decoder.
const string DefaultContentType
text/plain
Helps with common XML-related tasks.
Definition: XML.cs:19
static string Attribute(XmlElement E, string Name)
Gets the value of an XML attribute.
Definition: XML.cs:914
static string Encode(string s)
Encodes a string for use in XML.
Definition: XML.cs:27
Event arguments for message events.
bool Ok
If the response is an OK result response (true), or an error response (false).
XmlElement Content
Content of the message. For messages that are processed by registered message handlers,...
XmppException StanzaError
Any stanza error returned.
Client providing support for server mail-extension.
Definition: MailClient.cs:18
Task AppendContent(string ContentId, string ContentType, byte[] ContentData, ContentDisposition Disposition, string Name, string FileName, string Description, StringBuilder Xml)
Appends embedded content to a message XML output.
Definition: MailClient.cs:315
EventHandlerAsync< MailEventArgs > MailReceived
This event is raised when a mail message has been received.
Definition: MailClient.cs:176
Task Delete(string ObjectId, EventHandlerAsync< IqResultEventArgs > Callback, object State)
Deletes a message object from the broker.
Definition: MailClient.cs:276
Task Get(string ObjectId, string ContentType, EventHandlerAsync< MessageObjectEventArgs > Callback, object State)
Gets a message object from the broker.
Definition: MailClient.cs:196
Task< MessageObject > GetAsync(string ObjectId)
Gets a message object from the broker.
Definition: MailClient.cs:242
Task Get(string ObjectId, EventHandlerAsync< MessageObjectEventArgs > Callback, object State)
Gets a message object from the broker.
Definition: MailClient.cs:184
override void Dispose()
Disposes of the extension.
Definition: MailClient.cs:35
async Task< MessageObject > GetAsync(string ObjectId, string ContentType)
Gets a message object from the broker.
Definition: MailClient.cs:252
async Task DeleteAsync(string ObjectId)
Deletes a message object from the broker.
Definition: MailClient.cs:286
const string NamespaceMail
http://jabber.org/protocol/pubsub
Definition: MailClient.cs:22
override string[] Extensions
Implemented extensions.
Definition: MailClient.cs:45
MailClient(XmppClient Client)
Client providing support for server mail-extension.
Definition: MailClient.cs:28
Contains the binary representation of a message object.
Manages an XMPP client connection. Implements XMPP, as defined in https://tools.ietf....
Definition: XmppClient.cs:59
bool UnregisterMessageHandler(string LocalName, string Namespace, EventHandlerAsync< MessageEventArgs > Handler, bool RemoveNamespaceAsClientFeature)
Unregisters a Message handler.
Definition: XmppClient.cs:2855
void RegisterMessageHandler(string LocalName, string Namespace, EventHandlerAsync< MessageEventArgs > Handler, bool PublishNamespaceAsClientFeature)
Registers a Message handler.
Definition: XmppClient.cs:2828
string Domain
Current Domain.
Definition: XmppClient.cs:3453
Task< uint > SendIqGet(string To, string Xml, EventHandlerAsync< IqResultEventArgs > Callback, object State)
Sends an IQ Get request.
Definition: XmppClient.cs:3559
Base class for XMPP Extensions.
XmppClient client
XMPP Client used by the extension.
Task Exception(Exception Exception)
Called to inform the viewer of an exception state.
XmppClient Client
XMPP Client.
ContentDisposition
Content disposition
Priority
Mail priority
Definition: Priority.cs:7