summaryrefslogtreecommitdiff
path: root/protocols/YAMN/src/mails/mails.cpp
blob: 1bcbc60242a1d3c308cbee3d267c34c2bf5d3adb (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
/*
 * This code implements retrieving info from MIME header 
 *
 * (c) majvan 2002-2004
 */

#include "../stdafx.h"

/////////////////////////////////////////////////////////////////////////////////////////
// Creates new mail for plugin (calling plugin's constructor, when plugin imported to YAMN)

HYAMNMAIL CreateAccountMail(CAccount *Account)
{
	HYAMNMAIL NewMail;

	if (Account->Plugin == nullptr)
		return NULL;

	if (Account->Plugin->MailFcn->NewMailFcnPtr != nullptr) {
		// Let plugin create its own structure, which can be derived from CAccount structure
		if (nullptr == (NewMail = Account->Plugin->MailFcn->NewMailFcnPtr(Account)))
			return NULL;
	}
	else {
		// We suggest plugin uses standard CAccount structure, so we create it
		NewMail = new YAMNMAIL();
		NewMail->MailData = nullptr;
	}
	// Init every members of structure, used by YAMN
	return NewMail;
}

/////////////////////////////////////////////////////////////////////////////////////////
// Deletes mail for plugin (calling plugin's destructor, when plugin imported to YAMN)

int DeleteAccountMail(YAMN_PROTOPLUGIN *Plugin, HYAMNMAIL OldMail)
{
	struct CMimeItem *TH;

	if (Plugin->MailFcn != nullptr) {
		if (Plugin->MailFcn->DeleteMailFcnPtr != nullptr) {
			// Let plugin delete its own CMimeMsgQueue derived structure
			Plugin->MailFcn->DeleteMailFcnPtr(OldMail);
			return 1;
		}
	}
	if (OldMail->MailData != nullptr) {
		if (OldMail->MailData->Body != nullptr)
			delete[] OldMail->MailData->Body;
		if ((TH = OldMail->MailData->TranslatedHeader) != nullptr)
			for (; OldMail->MailData->TranslatedHeader != nullptr;) {
				TH = TH->Next;
				if (OldMail->MailData->TranslatedHeader->name != nullptr)
					delete[] OldMail->MailData->TranslatedHeader->name;
				if (OldMail->MailData->TranslatedHeader->value != nullptr)
					delete[] OldMail->MailData->TranslatedHeader->value;
				delete OldMail->MailData->TranslatedHeader;
				OldMail->MailData->TranslatedHeader = TH;
			}
		delete OldMail->MailData;
	}
	if (OldMail->ID != nullptr)
		delete[] OldMail->ID;

	delete OldMail;				// consider mail as standard HYAMNMAIL, not initialized before and use its own destructor
	return 1;
}

/////////////////////////////////////////////////////////////////////////////////////////
// Appends second MIME mail queue to the first one
// Only finds the end of first queue and its Next memember repoints to second one

void AppendQueueFcn(HYAMNMAIL first, HYAMNMAIL second)
{
	HYAMNMAIL Finder = first;
	while (Finder->Next != nullptr) Finder = Finder->Next;
	Finder->Next = second;
}

/////////////////////////////////////////////////////////////////////////////////////////
// Synchronizes two accounts
//
// Function finds, if there were some mails deleted from mailbox and deletes (depends on RemovedOld param) them from OldQueue
// Next finds, if there are new mails. Mails that are still on mailbox are deleted (depends on RemovedNew param) from NewQueue
// After this, OldQueue is pointer to mails that are on mailbox, but not new mails
// and NewQueue contains new mails in account
// New accounts can be then appended to account mails queue, but they have set the New flag
// 
// Two mails equals if they have the same ID
// 
// hPlugin- handle of plugin going to delete mails
// OldQueue- queue of mails that we found on mailbox last time, after function finishes queue contains all mails except new ones
// RemovedOld- queue of mails where to store removed mails from OldQueue, if NULL deletes mails from OldQueue
// NewQueue- queue of mails that we found on mailbox (all mails), after function finishes queue contains only new mails
// RemovedNew- queue of mails where to store removed mails from NewQueue, if NULL deletes mails from NewQueue
// So function works like:
// 1. delete (or move to RemovedOld queue if RemovedOld is not NULL) all mails from OldQueue not found in NewQueue
// 2. delete (or move to RemovedNew queue if RemovedNew is not NULL) all mails from NewQueue found in OldQueue

void SynchroMessagesFcn(CAccount *Account, HYAMNMAIL *OldQueue, HYAMNMAIL *RemovedOld, HYAMNMAIL *NewQueue, HYAMNMAIL *RemovedNew)
// deletes messages from new queue, if they are old
// it also deletes messages from old queue, if they are not in mailbox anymore
// "YAMN_MSG_DELETED" messages in old queue remain in old queue (are never removed, although they are not in new queue)
// "YAMN_MSG_DELETED" messages in new queue remain in new queue (are never removed, although they can be in old queue)
{
	HYAMNMAIL Finder, FinderPrev;
	HYAMNMAIL Parser, ParserPrev;
	HYAMNMAIL RemovedOldParser = nullptr;
	HYAMNMAIL RemovedNewParser = nullptr;
	if (RemovedOld != nullptr) *RemovedOld = nullptr;
	if (RemovedNew != nullptr) *RemovedNew = nullptr;

	for (FinderPrev = nullptr, Finder = *OldQueue; Finder != nullptr;) {
		if (Finder->Flags & YAMN_MSG_DELETED)        // if old queue contains deleted mail
		{
			FinderPrev = Finder;
			Finder = Finder->Next;                    // get next message in old queue for testing
			continue;
		}
		for (ParserPrev = nullptr, Parser = *NewQueue; Parser != nullptr; ParserPrev = Parser, Parser = Parser->Next) {
			if (Parser->Flags & YAMN_MSG_DELETED)
				continue;

			if (Parser->ID == nullptr)						// simply ignore the message, that has not filled its ID
				continue;

			if (0 == mir_strcmp(Parser->ID, Finder->ID))	// search for equal message in new queue
				break;
		}

		if (Parser != nullptr) {                     // found equal message in new queue
			if (Parser == *NewQueue)
				*NewQueue = (*NewQueue)->Next;
			else
				ParserPrev->Next = Parser->Next;
			Finder->Number = Parser->Number;				// rewrite the number of current message in old queue

			if (RemovedNew == nullptr)                // delete from new queue
				DeleteAccountMail(Account->Plugin, Parser);
			else {                                    // or move to RemovedNew
				if (RemovedNewParser == nullptr)       // if it is first mail removed from NewQueue
					*RemovedNew = Parser;               // set RemovedNew queue to point to first message in removed queue
				else
					RemovedNewParser->Next = Parser;		// else don't forget to show to next message in RemovedNew queue
				RemovedNewParser = Parser;             // follow RemovedNew queue
				RemovedNewParser->Next = nullptr;
			}
			FinderPrev = Finder;
			Finder = Finder->Next;                    // get next message in old queue for testing
		}
		else {                                       // a message was already deleted from mailbox
			if (Finder == *OldQueue) {                // if we are at the first item in OldQueue
				*OldQueue = (*OldQueue)->Next;			// set OldQueue to next item
				if (RemovedOld == nullptr)					// delete from old queue
					DeleteAccountMail(Account->Plugin, Finder);
				else {                                 // or move to RemovedOld
					if (RemovedOldParser == nullptr)    // if it is first mail removed from OldQueue
						*RemovedOld = Finder;            // set RemovedOld queue to point to first message in removed queue
					else
						RemovedOldParser->Next = Finder; // else don't forget to show to next message in RemovedNew queue
					RemovedOldParser = Finder;          // follow RemovedOld queue
					RemovedOldParser->Next = nullptr;
				}
				Finder = *OldQueue;
			}
			else {
				FinderPrev->Next = Finder->Next;
				// delete from old queue
				if (RemovedOld == nullptr)					
					DeleteAccountMail(Account->Plugin, Finder);
				// or move to RemovedOld
				else {
					if (RemovedOldParser == nullptr)    // if it is first mail removed from OldQueue
						*RemovedOld = Finder;            // set RemovedOld queue to point to first message in removed queue
					else
						RemovedOldParser->Next = Finder; // else don't forget to show to next message in RemovedNew queue
					RemovedOldParser = Finder;          // follow RemovedOld queue
					RemovedOldParser->Next = nullptr;
				}
				Finder = FinderPrev->Next;
			}
		}
	}
}

/////////////////////////////////////////////////////////////////////////////////////////
// Deletes messages from mail From to the end
// Account- account who owns mails
// From- first mail in queue, which is going to delete

void DeleteMessagesToEndFcn(CAccount *Account, HYAMNMAIL From)
{
	HYAMNMAIL Temp;
	while (From != nullptr) {
		Temp = From;
		From = From->Next;
		DeleteAccountMail(Account->Plugin, Temp);
	}
}

/////////////////////////////////////////////////////////////////////////////////////////
// Removes message from queue, does not delete from memory
// From- queue pointer
// Which- mail to delete
// mode- nonzero if you want to decrement numbers in messages that are bigger than the one in Which mail, 0 if not

void DeleteMessageFromQueueFcn(HYAMNMAIL *From, HYAMNMAIL Which, int mode)
{
	uint32_t Number = Which->Number;
	HYAMNMAIL Parser;

	if (*From == Which) {
		Parser = Which->Next;
		*From = Parser;
	}
	else {
		for (Parser = *From; Which != Parser->Next; Parser = Parser->Next)
			if (mode && (Parser->Number > Number)) Parser->Number--;
		if (mode && (Parser->Number > Number)) Parser->Number--;
		Parser->Next = Parser->Next->Next;
		Parser = Which->Next;
	}
	if (mode)
		for (; Parser != nullptr; Parser = Parser->Next)
			if (Parser->Number > Number) Parser->Number--;
}

void DeleteMessagesFromQueue(HYAMNMAIL *From, HYAMNMAIL Which, int mode = 0)
{
	HYAMNMAIL Parser;

	for (Parser = Which; Parser != nullptr; Parser = Parser->Next)
		DeleteMessageFromQueueFcn(From, Parser, mode);
}

/////////////////////////////////////////////////////////////////////////////////////////
// Finds message in queue that has the same ID number
// From- message queue
// ID- pointer to ID
// returns pointer to found message, NULL if not found

HYAMNMAIL FindMessageByIDFcn(HYAMNMAIL From, char *ID)
{
	HYAMNMAIL Browser;

	for (Browser = From; Browser != nullptr; Browser = Browser->Next)
		if (0 == mir_strcmp(Browser->ID, ID))
			break;
	return Browser;
}

/////////////////////////////////////////////////////////////////////////////////////////
// Translate header from text to queue of CMimeItem structures
// This means that new queue will contain all info about headers
// stream- pointer to text containing header (can be ended with zero)
// len- length of stream
// head- function fills this pointer to first header item in queue

void TranslateHeaderFcn(char *stream, int len, struct CMimeItem **head)
{
	try {
		char *finder = stream;
		char *prev1, *prev2, *prev3;
		struct CMimeItem *Item = nullptr;

		while (finder <= (stream + len)) {
			while (ENDLINEWS(finder)) finder++;

			// at the start of line
			if (DOTLINE(finder + 1))					// at the end of stream
				break;

			prev1 = finder;

			while (*finder != ':' && !EOS(finder)) finder++;
			if (!EOS(finder))
				prev2 = finder++;
			else
				break;

			while (WS(finder) && !EOS(finder)) finder++;
			if (!EOS(finder))
				prev3 = finder;
			else
				break;

			do {
				if (ENDLINEWS(finder)) finder += 2;						// after endline information continues
				while (!ENDLINE(finder) && !EOS(finder)) finder++;
			} while (ENDLINEWS(finder));

			if (Item != nullptr) {
				if (nullptr == (Item->Next = new CMimeItem()))
					break;
				Item = Item->Next;
			}
			else {
				Item = new CMimeItem;
				*head = Item;
			}

			Item->Next = nullptr;
			Item->name = new char[prev2 - prev1 + 1];
			mir_strncpy(Item->name, prev1, prev2 - prev1 + 1);
			Item->value = new char[finder - prev3 + 1];
			mir_strncpy(Item->value, prev3, finder - prev3 + 1);

			if (EOS(finder))
				break;
			finder++;
			if (ENDLINE(finder)) {
				finder++;
				if (ENDLINE(finder)) {
					// end of headers. message body begins
					finder++;
					if (ENDLINE(finder))finder++;
					prev1 = finder;
					while (!DOTLINE(finder + 1))finder++;
					if (ENDLINE(finder))finder--;
					prev2 = finder;
					if (prev2 > prev1) { // yes, we have body
						Item->Next = new CMimeItem();
						Item = Item->Next;
						Item->Next = nullptr;// just in case;
						Item->name = new char[5]; strncpy(Item->name, "Body", 5);
						Item->value = new char[prev2 - prev1];
						mir_strncpy(Item->value, prev1, prev2 - prev1 - 1);
					}
					break; // there is nothing else
				}
			}
		}
	}
	catch (...) {
		MessageBoxA(nullptr, "Translate header error", "", 0);
	}
}

/////////////////////////////////////////////////////////////////////////////////////////
// Creates new mail queue, copying only these mails, that have set flag for deleting
// From- message queue, whose mail with given flag are duplicated
// returns new mail queue (or NULL when no mail with flag is in From queue)
// Function does not copy the whole mails, it copies only ID string. And ID is copied as string, so
// you can use this fcn only if you have your ID as pointer to char string ended with zero character

HYAMNMAIL CreateNewDeleteQueueFcn(HYAMNMAIL From)
{
	HYAMNMAIL FirstMail, Browser = nullptr;

	for (FirstMail = nullptr; From != nullptr; From = From->Next) {
		if ((From->Flags & (YAMN_MSG_USERDELETE | YAMN_MSG_AUTODELETE)) && !(From->Flags & YAMN_MSG_DELETED)) {
			if (FirstMail == nullptr) {
				FirstMail = Browser = new YAMNMAIL;
				if (FirstMail == nullptr)
					break;
			}
			else {
				Browser->Next = new YAMNMAIL;
				Browser = Browser->Next;
			}
			Browser->ID = new char[mir_strlen(From->ID) + 1];
			mir_strcpy(Browser->ID, From->ID);
			Browser->Number = From->Number;
			Browser->Flags = From->Flags;
		}
	}
	return FirstMail;
}

/////////////////////////////////////////////////////////////////////////////////////////
// Sets/removes flags from specific mails
// From- pointer to first message
// FlagsSet- mail must have set these flags...
// FlagsNotSet- ...and must not have set these flags...
// FlagsToSetRemove- ...to set/remove these flags (see mode)
// mode- nonzero to set, else remove

void SetRemoveFlagsInQueueFcn(HYAMNMAIL From, uint32_t FlagsSet, uint32_t FlagsNotSet, uint32_t FlagsToSetRemove, int mode)
{
	HYAMNMAIL msgq;

	for (msgq = (HYAMNMAIL)From; msgq != nullptr; msgq = msgq->Next) {
		if ((FlagsSet == (msgq->Flags & FlagsSet)) && (0 == (msgq->Flags & FlagsNotSet))) {
			if (mode)
				msgq->Flags = msgq->Flags | FlagsToSetRemove;
			else
				msgq->Flags = msgq->Flags & ~FlagsToSetRemove;
		}
	}
}