1 /* 2 * Copyright 2011-2013, Haiku, Inc. All rights reserved. 3 * Copyright 2001-2003 Dr. Zoidberg Enterprises. All rights reserved. 4 */ 5 6 7 //#include <assert.h> 8 #include <stdio.h> 9 #include <stdlib.h> 10 11 #include <fs_attr.h> 12 13 #include <Alert.h> 14 #include <Directory.h> 15 #include <FindDirectory.h> 16 #include <E-mail.h> 17 #include <Locker.h> 18 #include <Node.h> 19 #include <NodeInfo.h> 20 #include <NodeMonitor.h> 21 #include <Path.h> 22 #include <Query.h> 23 #include <Roster.h> 24 #include <String.h> 25 #include <StringList.h> 26 #include <VolumeRoster.h> 27 28 #include <MailFilter.h> 29 #include <MailDaemon.h> 30 #include <MailProtocol.h> 31 #include <MailSettings.h> 32 33 #include <mail_util.h> 34 #include <MailPrivate.h> 35 #include <NodeMessage.h> 36 37 #include "HaikuMailFormatFilter.h" 38 39 40 using namespace BPrivate; 41 42 43 const uint32 kMsgDeleteMessage = '&DeM'; 44 const uint32 kMsgAppendMessage = '&ApM'; 45 46 const uint32 kMsgSendMessage = '&SeM'; 47 48 49 BMailProtocol::BMailProtocol(const BMailAccountSettings& settings) 50 : 51 fAccountSettings(settings), 52 fMailNotifier(NULL) 53 { 54 AddFilter(new HaikuMailFormatFilter(*this, settings)); 55 } 56 57 58 BMailProtocol::~BMailProtocol() 59 { 60 delete fMailNotifier; 61 62 for (int i = 0; i < fFilterList.CountItems(); i++) 63 delete fFilterList.ItemAt(i); 64 65 std::map<entry_ref, image_id>::iterator it = fFilterImages.begin(); 66 for (; it != fFilterImages.end(); it++) 67 unload_add_on(it->second); 68 } 69 70 71 const BMailAccountSettings& 72 BMailProtocol::AccountSettings() const 73 { 74 return fAccountSettings; 75 } 76 77 78 void 79 BMailProtocol::SetMailNotifier(BMailNotifier* mailNotifier) 80 { 81 delete fMailNotifier; 82 fMailNotifier = mailNotifier; 83 } 84 85 86 BMailNotifier* 87 BMailProtocol::MailNotifier() const 88 { 89 return fMailNotifier; 90 } 91 92 93 bool 94 BMailProtocol::AddFilter(BMailFilter* filter) 95 { 96 BLocker locker(this); 97 return fFilterList.AddItem(filter); 98 } 99 100 101 int32 102 BMailProtocol::CountFilter() const 103 { 104 BLocker locker(this); 105 return fFilterList.CountItems(); 106 } 107 108 109 BMailFilter* 110 BMailProtocol::FilterAt(int32 index) const 111 { 112 BLocker locker(this); 113 return fFilterList.ItemAt(index); 114 } 115 116 117 BMailFilter* 118 BMailProtocol::RemoveFilter(int32 index) 119 { 120 BLocker locker(this); 121 return fFilterList.RemoveItemAt(index); 122 } 123 124 125 bool 126 BMailProtocol::RemoveFilter(BMailFilter* filter) 127 { 128 BLocker locker(this); 129 return fFilterList.RemoveItem(filter); 130 } 131 132 133 void 134 BMailProtocol::MessageReceived(BMessage* message) 135 { 136 BLooper::MessageReceived(message); 137 } 138 139 140 status_t 141 BMailProtocol::MoveMessage(const entry_ref& ref, BDirectory& dir) 142 { 143 BEntry entry(&ref); 144 return entry.MoveTo(&dir); 145 } 146 147 148 status_t 149 BMailProtocol::DeleteMessage(const entry_ref& ref) 150 { 151 BEntry entry(&ref); 152 return entry.Remove(); 153 } 154 155 156 void 157 BMailProtocol::ShowError(const char* error) 158 { 159 if (MailNotifier() != NULL) 160 MailNotifier()->ShowError(error); 161 } 162 163 164 void 165 BMailProtocol::ShowMessage(const char* message) 166 { 167 if (MailNotifier() != NULL) 168 MailNotifier()->ShowMessage(message); 169 } 170 171 172 void 173 BMailProtocol::SetTotalItems(uint32 items) 174 { 175 if (MailNotifier() != NULL) 176 MailNotifier()->SetTotalItems(items); 177 } 178 179 180 void 181 BMailProtocol::SetTotalItemsSize(uint64 size) 182 { 183 if (MailNotifier() != NULL) 184 MailNotifier()->SetTotalItemsSize(size); 185 } 186 187 188 void 189 BMailProtocol::ReportProgress(uint32 messages, uint64 bytes, 190 const char* message) 191 { 192 if (MailNotifier() != NULL) 193 MailNotifier()->ReportProgress(messages, bytes, message); 194 } 195 196 197 void 198 BMailProtocol::ResetProgress(const char* message) 199 { 200 if (MailNotifier() != NULL) 201 MailNotifier()->ResetProgress(message); 202 } 203 204 205 void 206 BMailProtocol::NotifyNewMessagesToFetch(int32 count) 207 { 208 ResetProgress(); 209 SetTotalItems(count); 210 } 211 212 213 BMailFilterAction 214 BMailProtocol::ProcessHeaderFetched(entry_ref& ref, BFile& file, 215 BMessage& attributes) 216 { 217 BMailFilterAction action = _ProcessHeaderFetched(ref, file, attributes); 218 if (action >= B_OK && action != B_DELETE_MAIL_ACTION) 219 file << attributes; 220 221 return action; 222 } 223 224 225 void 226 BMailProtocol::NotifyBodyFetched(const entry_ref& ref, BFile& file, 227 BMessage& attributes) 228 { 229 _NotifyBodyFetched(ref, file, attributes); 230 file << attributes; 231 } 232 233 234 BMailFilterAction 235 BMailProtocol::ProcessMessageFetched(entry_ref& ref, BFile& file, 236 BMessage& attributes) 237 { 238 BMailFilterAction action = _ProcessHeaderFetched(ref, file, attributes); 239 if (action >= B_OK && action != B_DELETE_MAIL_ACTION) { 240 _NotifyBodyFetched(ref, file, attributes); 241 file << attributes; 242 } 243 244 return action; 245 } 246 247 248 void 249 BMailProtocol::NotifyMessageReadyToSend(const entry_ref& ref, BFile& file) 250 { 251 for (int i = 0; i < fFilterList.CountItems(); i++) 252 fFilterList.ItemAt(i)->MessageReadyToSend(ref, file); 253 } 254 255 256 void 257 BMailProtocol::NotifyMessageSent(const entry_ref& ref, BFile& file) 258 { 259 for (int i = 0; i < fFilterList.CountItems(); i++) 260 fFilterList.ItemAt(i)->MessageSent(ref, file); 261 } 262 263 264 void 265 BMailProtocol::LoadFilters(const BMailProtocolSettings& settings) 266 { 267 for (int i = 0; i < settings.CountFilterSettings(); i++) { 268 BMailAddOnSettings* filterSettings = settings.FilterSettingsAt(i); 269 BMailFilter* filter = _LoadFilter(*filterSettings); 270 if (filter != NULL) 271 AddFilter(filter); 272 } 273 } 274 275 276 BMailFilter* 277 BMailProtocol::_LoadFilter(const BMailAddOnSettings& settings) 278 { 279 const entry_ref& ref = settings.AddOnRef(); 280 std::map<entry_ref, image_id>::iterator it = fFilterImages.find(ref); 281 image_id image; 282 if (it != fFilterImages.end()) 283 image = it->second; 284 else { 285 BEntry entry(&ref); 286 BPath path(&entry); 287 image = load_add_on(path.Path()); 288 } 289 if (image < 0) 290 return NULL; 291 292 BMailFilter* (*instantiateFilter)(BMailProtocol& protocol, 293 const BMailAddOnSettings& settings); 294 if (get_image_symbol(image, "instantiate_filter", B_SYMBOL_TYPE_TEXT, 295 (void**)&instantiateFilter) != B_OK) { 296 unload_add_on(image); 297 return NULL; 298 } 299 300 fFilterImages[ref] = image; 301 return instantiateFilter(*this, settings); 302 } 303 304 305 BMailFilterAction 306 BMailProtocol::_ProcessHeaderFetched(entry_ref& ref, BFile& file, 307 BMessage& attributes) 308 { 309 entry_ref outRef = ref; 310 311 for (int i = 0; i < fFilterList.CountItems(); i++) { 312 BMailFilterAction action = fFilterList.ItemAt(i)->HeaderFetched(outRef, 313 file, attributes); 314 if (action == B_DELETE_MAIL_ACTION) { 315 // We have to delete the message 316 BEntry entry(&ref); 317 status_t status = entry.Remove(); 318 if (status != B_OK) { 319 fprintf(stderr, "BMailProtocol::NotifyHeaderFetched(): could " 320 "not delete mail: %s\n", strerror(status)); 321 } 322 return B_DELETE_MAIL_ACTION; 323 } 324 } 325 326 if (ref == outRef) 327 return B_NO_MAIL_ACTION; 328 329 // We have to rename the file 330 node_ref newParentRef; 331 newParentRef.device = outRef.device; 332 newParentRef.node = outRef.directory; 333 334 BDirectory newParent(&newParentRef); 335 status_t status = newParent.InitCheck(); 336 BString workerName; 337 if (status == B_OK) { 338 int32 uniqueNumber = 1; 339 do { 340 workerName = outRef.name; 341 if (uniqueNumber > 1) 342 workerName << "_" << uniqueNumber; 343 344 // TODO: support copying to another device! 345 BEntry entry(&ref); 346 status = entry.Rename(workerName); 347 348 uniqueNumber++; 349 } while (status == B_FILE_EXISTS); 350 } 351 352 if (status != B_OK) { 353 fprintf(stderr, "BMailProtocol::NotifyHeaderFetched(): could not " 354 "rename mail (%s)! (should be: %s)\n", strerror(status), 355 workerName.String()); 356 } 357 358 ref = outRef; 359 ref.set_name(workerName.String()); 360 361 return B_MOVE_MAIL_ACTION; 362 } 363 364 365 void 366 BMailProtocol::_NotifyBodyFetched(const entry_ref& ref, BFile& file, 367 BMessage& attributes) 368 { 369 for (int i = 0; i < fFilterList.CountItems(); i++) 370 fFilterList.ItemAt(i)->BodyFetched(ref, file, attributes); 371 } 372 373 374 // #pragma mark - 375 376 377 BInboundMailProtocol::BInboundMailProtocol(const BMailAccountSettings& settings) 378 : 379 BMailProtocol(settings) 380 { 381 LoadFilters(fAccountSettings.InboundSettings()); 382 } 383 384 385 BInboundMailProtocol::~BInboundMailProtocol() 386 { 387 } 388 389 390 void 391 BInboundMailProtocol::MessageReceived(BMessage* message) 392 { 393 switch (message->what) { 394 case kMsgSyncMessages: 395 { 396 NotiyMailboxSynchronized(SyncMessages()); 397 break; 398 } 399 400 case kMsgFetchBody: 401 { 402 entry_ref ref; 403 message->FindRef("ref", &ref); 404 status_t status = FetchBody(ref); 405 406 BMessenger target; 407 if (message->FindMessenger("target", &target) != B_OK) 408 break; 409 410 BMessage message(B_MAIL_BODY_FETCHED); 411 message.AddInt32("status", status); 412 message.AddRef("ref", &ref); 413 target.SendMessage(&message); 414 break; 415 } 416 417 case kMsgMarkMessageAsRead: 418 { 419 entry_ref ref; 420 message->FindRef("ref", &ref); 421 read_flags read = (read_flags)message->FindInt32("read"); 422 MarkMessageAsRead(ref, read); 423 break; 424 } 425 426 case kMsgDeleteMessage: 427 { 428 entry_ref ref; 429 message->FindRef("ref", &ref); 430 DeleteMessage(ref); 431 break; 432 } 433 434 case kMsgAppendMessage: 435 { 436 entry_ref ref; 437 message->FindRef("ref", &ref); 438 AppendMessage(ref); 439 break; 440 } 441 442 default: 443 BMailProtocol::MessageReceived(message); 444 break; 445 } 446 } 447 448 449 status_t 450 BInboundMailProtocol::MarkMessageAsRead(const entry_ref& ref, read_flags flag) 451 { 452 BNode node(&ref); 453 return write_read_attr(node, flag); 454 } 455 456 457 status_t 458 BInboundMailProtocol::AppendMessage(const entry_ref& ref) 459 { 460 return B_OK; 461 } 462 463 464 void 465 BInboundMailProtocol::NotiyMailboxSynchronized(status_t status) 466 { 467 for (int32 i = 0; i < CountFilter(); i++) 468 FilterAt(i)->MailboxSynchronized(status); 469 } 470 471 472 // #pragma mark - 473 474 475 BOutboundMailProtocol::BOutboundMailProtocol( 476 const BMailAccountSettings& settings) 477 : 478 BMailProtocol(settings) 479 { 480 LoadFilters(fAccountSettings.OutboundSettings()); 481 } 482 483 484 BOutboundMailProtocol::~BOutboundMailProtocol() 485 { 486 } 487 488 489 void 490 BOutboundMailProtocol::MessageReceived(BMessage* message) 491 { 492 switch (message->what) { 493 case kMsgSendMessage: 494 SendMessages(*message, message->FindInt64("bytes")); 495 break; 496 497 default: 498 BMailProtocol::MessageReceived(message); 499 } 500 } 501