summaryrefslogtreecommitdiff
path: root/plugins/YAMN/src/mails/mails.cpp
blob: 28ba473e7b762572a0ebcef034ff2f28dade038b (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
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
/*
 * This code implements retrieving info from MIME header 
 *
 * (c) majvan 2002-2004
 */

#include "../stdafx.h"

//--------------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------------

// SMALL INTRO
// Mails are queued in a queue (chained list). Pointer to first mail is pointed from Account structure
// member called Mails.
// Mail queue is ended with NULL- pointered mail (NULL handle)

//Creates new mail for plugin (calling plugin's constructor, when plugin imported to YAMN)
INT_PTR CreateAccountMailSvc(WPARAM wParam,LPARAM lParam);

//Deletes mail for plugin (calling plugin's destructor, when plugin imported to YAMN)
INT_PTR DeleteAccountMailSvc(WPARAM wParam,LPARAM lParam);

//Loads mail data from standard storage to memory
INT_PTR LoadMailDataSvc(WPARAM wParam,LPARAM lParam);

//Deletes mail data from memory
INT_PTR UnloadMailDataSvc(WPARAM wParam,LPARAM);

//Saves mail data from memory to standard storage
INT_PTR SaveMailDataSvc(WPARAM wParam,LPARAM lParam);

//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 WINAPI AppendQueueFcn(HYAMNMAIL first,HYAMNMAIL 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 WINAPI SynchroMessagesFcn(HACCOUNT Account,HYAMNMAIL *OldQueue,HYAMNMAIL *RemovedOld,HYAMNMAIL *NewQueue,HYAMNMAIL *RemovedNew);

//Deletes messages from mail From to the end
// Account- account who owns mails
// From- first mail in queue, which is going to delete
void WINAPI DeleteMessagesToEndFcn(HACCOUNT Account,HYAMNMAIL From);

//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 WINAPI DeleteMessageFromQueueFcn(HYAMNMAIL *From,HYAMNMAIL Which,int 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 WINAPI FindMessageByIDFcn(HYAMNMAIL From,char *ID);

//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 WINAPI TranslateHeaderFcn(char *stream,int len,struct CMimeItem **head);

//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 WINAPI CreateNewDeleteQueueFcn(HYAMNMAIL From);

//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 WINAPI SetRemoveFlagsInQueueFcn(HYAMNMAIL From,DWORD FlagsSet,DWORD FlagsNotSet,DWORD FlagsToSetRemove,int mode);

struct CExportedFunctions MailExportedFcn[]=
{
	{YAMN_SYNCHROMIMEMSGSID,(void *)SynchroMessagesFcn},
	{YAMN_TRANSLATEHEADERID,(void *)TranslateHeaderFcn},
	{YAMN_APPENDQUEUEID,(void *)AppendQueueFcn},
	{YAMN_DELETEMIMEQUEUEID,(void *)DeleteMessagesToEndFcn},
	{YAMN_DELETEMIMEMESSAGEID,(void *)DeleteMessageFromQueueFcn},
	{YAMN_FINDMIMEMESSAGEID,(void *)FindMessageByIDFcn},
	{YAMN_CREATENEWDELETEQUEUEID,(void *)CreateNewDeleteQueueFcn},
	{YAMN_SETREMOVEQUEUEFLAGSID,(void *)SetRemoveFlagsInQueueFcn},
};

struct CExportedServices MailExportedSvc[]=
{
	{MS_YAMN_CREATEACCOUNTMAIL,CreateAccountMailSvc},
	{MS_YAMN_DELETEACCOUNTMAIL,DeleteAccountMailSvc},
	{MS_YAMN_LOADMAILDATA,LoadMailDataSvc},
	{MS_YAMN_UNLOADMAILDATA,UnloadMailDataSvc},
	{MS_YAMN_SAVEMAILDATA,SaveMailDataSvc},
};


//--------------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------------

INT_PTR CreateAccountMailSvc(WPARAM wParam,LPARAM lParam)
{
	HACCOUNT Account=(HACCOUNT)wParam;
	DWORD MailVersion=(DWORD)lParam;
	HYAMNMAIL NewMail;

//test if we are going to initialize members of suitable structure (structures of plugin and YAMN must match)
	if (MailVersion != YAMN_MAILVERSION)
		return NULL;

	if (Account->Plugin != nullptr)
	{
		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,YAMN_MAILVERSION)))
				return NULL;
		}
		else
		{
//We suggest plugin uses standard CAccount structure, so we create it
			if (nullptr==(NewMail=new YAMNMAIL))
//If not created successfully
				return NULL;
			NewMail->MailData=nullptr;
		}
//Init every members of structure, used by YAMN
		return (INT_PTR)NewMail;
	}
	return NULL;
}

INT_PTR DeleteAccountMailSvc(WPARAM wParam,LPARAM lParam)
{
	HYAMNPROTOPLUGIN Plugin=(HYAMNPROTOPLUGIN)wParam;
	HYAMNMAIL OldMail=(HYAMNMAIL)lParam;
	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;
}


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

INT_PTR LoadMailDataSvc(WPARAM wParam,LPARAM lParam)
{
	HYAMNMAIL Mail=(HYAMNMAIL)wParam;
	DWORD MailVersion=(DWORD)lParam;

	if (MailVersion != YAMN_MAILDATAVERSION)
		return NULL;

	// now we have all data to memory persisting, so no loading is needed
	return (INT_PTR)Mail->MailData;
}

INT_PTR UnloadMailDataSvc(WPARAM, LPARAM)
{
	return 1;
}

INT_PTR SaveMailDataSvc(WPARAM, LPARAM lParam)
{
	DWORD MailVersion=(DWORD)lParam;

	if (MailVersion != YAMN_MAILDATAVERSION)
		return (INT_PTR)-1;

	// now we have all data to memory persisting, so no saving is needed
	return (INT_PTR)0;
}

void WINAPI SynchroMessagesFcn(HACCOUNT 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
				DeleteAccountMailSvc((WPARAM)Account->Plugin,(LPARAM)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
					DeleteAccountMailSvc((WPARAM)Account->Plugin,(LPARAM)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;
				if (RemovedOld==nullptr)					//delete from old queue
					DeleteAccountMailSvc((WPARAM)Account->Plugin,(LPARAM)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=FinderPrev->Next;
			}
		}
	}
}

void WINAPI DeleteMessagesToEndFcn(HACCOUNT Account,HYAMNMAIL From)
{
	HYAMNMAIL Temp;
	while(From != nullptr)
	{
		Temp=From;
		From=From->Next;
		DeleteAccountMailSvc((WPARAM)Account->Plugin,(LPARAM)Temp);
	}
}

void WINAPI DeleteMessageFromQueueFcn(HYAMNMAIL *From,HYAMNMAIL Which,int mode=0)
{
	DWORD 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);
}

HYAMNMAIL WINAPI 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;
}

void WINAPI 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 struct 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
						if (nullptr==(Item->Next=new struct CMimeItem))	break; // Cant create new item?!
						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);
	}
}

HYAMNMAIL WINAPI 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;
}

void WINAPI SetRemoveFlagsInQueueFcn(HYAMNMAIL From,DWORD FlagsSet,DWORD FlagsNotSet,DWORD 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;
		}
	}
}