📄 msgc.c
字号:
/* * $Id: MsgC.C,v 1.3 2000/09/19 16:42:02 evgeny Exp $ * * Copyright (c) 1994 HAL Computer Systems International, Ltd. * * HAL COMPUTER SYSTEMS INTERNATIONAL, LTD. * 1315 Dell Avenue * Campbell, CA 95008 * * Author: Greg Hilton * Contributors: Tom Lang, Frank Bieser, and others * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * http://www.gnu.org/copyleft/gpl.html * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */#include <config.h>#include "MsgC.h"#include "AddressC.h"#include "HeaderC.h"#include "HeaderValC.h"#include "MsgPartC.h"#include "FolderC.h"#include "IshAppC.h"#include "HeadPrefC.h"#include "MsgItemC.h"#include "MainWinC.h"#include "RuleDictC.h"#include "date.h"#include "ReplyPrefC.h"#include "TermFn.h"#include "SendWinC.h"#include <hgl/RegexC.h>#include <hgl/StringC.h>#include <hgl/CharC.h>#include <hgl/PtrListC.h>#include <hgl/StringListC.h>#include <hgl/SysErr.h>#include <unistd.h>#include <errno.h>RegexC *MsgC::rePat = NULL;extern int debuglev;/*--------------------------------------------------------------- * Constructor */MsgC::MsgC(FolderC *fld){ if ( !rePat ) rePat = new RegexC("^[ \t]*[Rr][Ee][[(]?[0-9]*[])]?:[ \t]*"); status = MSG_NEW; epochTime = 0; folder = fld; from = NULL; to = NULL; cc = NULL; replyTo = NULL; returnPath = NULL; sender = NULL; thread = NULL; indexOffset = -1; number = 0; headWritePos = 0; bodyWritePos = 0; icon = NULL; bodySizeKnown = False; body = new MsgPartC; body->parentMsg = this;} // End constructor/*--------------------------------------------------------------- * Destructor */MsgC::~MsgC(){//// Notify all composition windows// u_int count = ishApp->sendWinList.size(); for (int i=0; i<count; i++) { SendWinC *win = (SendWinC*)*ishApp->sendWinList[i]; if ( win->IsShown() ) win->MessageDeleted(this); } delete from; delete to; delete cc; delete replyTo; delete returnPath; delete sender; delete thread; delete icon; delete body;}/*--------------------------------------------------------------- * Method to add a new header to the linked list and check it's * attributes. */voidMsgC::CheckHeader(HeaderC *head){//// Check for Content- headers// if ( head->key.StartsWith("Content-", IGNORE_CASE) || head->key.StartsWith("X-Content-", IGNORE_CASE) ) {//// Look for sun attachments// if ( head->key.Equals("content-type", IGNORE_CASE) ) { CharC full(head->full); if ( full.Contains("X-Sun-Attachment", IGNORE_CASE) ) SetStatus(MSG_SUN_ATTACH); else if ( full.Contains("message/partial", IGNORE_CASE) ) SetStatus(MSG_PARTIAL); } } // End if this is a Content- header//// Check for other special headers// else switch (head->key.Length()) { case 2: if ( head->key.Equals("To", IGNORE_CASE) ) AddAddress(head, &to); else if ( head->key.Equals("Cc", IGNORE_CASE) ) AddAddress(head, &cc); break; case 4: if ( head->key.Equals("From", IGNORE_CASE) ) AddAddress(head, &from); else if ( head->key.Equals("Date", IGNORE_CASE) ) { StringC tmp; head->GetValueText(tmp); epochTime = parsedate(tmp, NULL); } break; case 6: if ( head->key.Equals("Sender", IGNORE_CASE) ) AddAddress(head, &sender); else if ( head->key.Equals("Status", IGNORE_CASE) ) { ClearStatus(MSG_NEW); CharC full(head->full); if ( full.Contains('R') ) SetStatus(MSG_READ); else ClearStatus(MSG_READ); } break; case 7: if ( head->key.Equals("Subject", IGNORE_CASE) && !thread ) GetThread(head); break; case 8: if ( head->key.Equals("Reply-To", IGNORE_CASE) ) AddAddress(head, &replyTo); break; case 10: if ( head->key.Equals("Message-Id", IGNORE_CASE) ) head->GetValueText(msgId); break; case 11: if ( head->key.Equals("Return-Path", IGNORE_CASE) ) AddAddress(head, &returnPath); break; case 12: if ( head->key.Equals("Mime-Version", IGNORE_CASE) ) SetStatus(MSG_MIME); break; } // End switch length} // End CheckHeader/*--------------------------------------------------------------- * Method to add a new header to the linked list and check it's * attributes. */voidMsgC::AddAddress(HeaderC *head, AddressC **addr){ AddressC *newAddr = new AddressC(head->value->full); if ( !*addr ) *addr = newAddr; else { AddressC *last = *addr; while ( last->next ) last = last->next; last->next = newAddr; }} // End AddAddress/*------------------------------------------------------------------------ * Method to extract the thread string. This is the subject without any * Re's or (fwd)'s */voidMsgC::GetThread(HeaderC *head){//// Remove Re's at the beginning// StringC threadStr; head->GetValueText(threadStr); Boolean done = False; while ( !done ) { if ( rePat->match(threadStr) ) threadStr.CutBeg((*rePat)[0].length()); else if ( threadStr.StartsWith("fwd:", IGNORE_CASE) ) threadStr.CutBeg(4); else if ( threadStr.StartsWith("(fwd)", IGNORE_CASE) ) threadStr.CutBeg(5); else if ( threadStr.EndsWith("(fwd)", IGNORE_CASE) ) threadStr.CutEnd(5); else done = True; threadStr.Trim(); } thread = new char[threadStr.size()+1]; strcpy(thread, threadStr);} // End GetThread/*--------------------------------------------------------------- * Method to print message to stream. */voidMsgC::Print(ostream& strm) const{ if ( body->headers && debuglev > 1 ) { strm <<"........................................" <<endl; HeaderC *head = body->headers; while ( head ) { strm <<*head; head = head->next; } strm <<"........................................" <<endl; } if ( from ) strm <<" From: " <<*from <<endl; if ( to ) strm <<" To: " <<*to <<endl; if ( cc ) strm <<" Cc: " <<*cc <<endl; if ( debuglev > 1 ) { if ( replyTo ) strm <<" Reply-To: " <<*replyTo <<endl; if ( returnPath ) strm <<"Return-Path: " <<*returnPath <<endl; if ( sender ) strm <<" Sender: " <<*sender <<endl; if ( thread ) strm <<" Thread: " <<thread <<endl; } HeaderValC *val = Date(); if ( val ) strm <<" Date: " <<*val <<endl; strm <<"Status: "; if ( IsSet(MSG_NEW) ) strm <<"New "; if ( IsSet(MSG_READ) ) strm <<"Read "; if ( IsSet(MSG_DELETED) ) strm <<"Deleted "; if ( IsSet(MSG_SAVED) ) strm <<"Saved "; if ( IsSet(MSG_REPLIED) ) strm <<"Replied "; if ( IsSet(MSG_FORWARDED) ) strm <<"Forwarded "; if ( IsSet(MSG_RESENT) ) strm <<"Resent "; if ( IsSet(MSG_PRINTED) ) strm <<"Printed "; if ( IsSet(MSG_FILTERED) ) strm <<"Filtered "; if ( IsSet(MSG_FLAGGED) ) strm <<"Flagged "; if ( IsSet(MSG_MIME) ) strm <<"Mime "; if ( IsSet(MSG_SUN_ATTACH) ) strm <<"Sun "; if ( IsSet(MSG_OPEN_FROMS) ) strm <<"Open-froms "; if ( IsSet(MSG_SAFE_FROMS) ) strm <<"Safe-froms "; if ( IsSet(MSG_FROMS_CHECKED) ) strm <<"Froms-checked "; if ( IsSet(MSG_VIEWED) ) strm <<"Viewed "; if ( IsSet(MSG_IN_USE) ) strm <<"In-use "; if ( IsSet(MSG_CHANGED) ) strm <<"Changed "; if ( IsSet(MSG_PARTIAL) ) strm <<"Partial "; if (!body->IsPlainText() ) strm <<"Not-plain "; if ( body->IsEncoded() ) strm <<"Encoded "; strm <<endl; strm <<"........................................" <<endl; strm <<*body; strm <<"........................................" <<endl;}/*------------------------------------------------------------------------ * Method to set number */voidMsgC::SetNumber(int num){ number = num; if ( icon ) icon->UpdateStatus();}/*------------------------------------------------------------------------ * Method to set status flags. If VIEWED is being set, we will also set * READ. */voidMsgC::SetStatus(MsgStatusT val, Boolean write){ if ( (status & (u_int)val) != 0 ) return; // Already set status |= (u_int)val; if ( !folder ) return;//// Viewed implies read// if ( val == MSG_VIEWED ) { if ( IsRead() ) write = False; else { status |= (u_int) MSG_READ; status &= (u_int)~MSG_NEW; status |= (u_int) MSG_CHANGED; folder->MsgStatusChanged(this); } } else { if ( val == MSG_READ ) status &= (u_int)~MSG_NEW; else if ( val == MSG_NEW ) status &= (u_int)~MSG_READ; if ( val == MSG_DELETED ) folder->MsgDeleted(this); else if ( val == MSG_NEW || val == MSG_READ ) folder->MsgStatusChanged(this); status |= (u_int)MSG_CHANGED; //folder->SetChanged(True); }//// Update index file// if ( write && indexOffset >= 0 && folder && folder->writable ) folder->UpdateIndexEntry(this);//// Update visible icon// if ( icon ) icon->UpdateStatus();} // End SetStatus/*------------------------------------------------------------------------ * Method to clear status flags */voidMsgC::ClearStatus(MsgStatusT val, Boolean write){ if ( (status & (u_int)val) == 0 ) return; // Already clear status &= ~(u_int)val; if ( !folder ) return; if ( val != MSG_VIEWED ) { if ( val == MSG_DELETED ) folder->MsgUndeleted(this); else if ( val == MSG_NEW || val == MSG_READ ) folder->MsgStatusChanged(this); if ( val != MSG_CHANGED ) { status |= (u_int)MSG_CHANGED; //folder->SetChanged(True); }//// Update index file// if ( write && indexOffset >= 0 && folder && folder->writable ) folder->UpdateIndexEntry(this); } // End if not clearing VIEWED//// Update visible icon// if ( icon ) icon->UpdateStatus();} // End ClearStatus/*------------------------------------------------------------------------ * Method to check status flags */BooleanMsgC::IsSet(MsgStatusT val) const{ return ((status & (u_int)val) != 0);}/*------------------------------------------------------------------------ * Method to return the string representation of the status */voidMsgC::GetStatusString(StringC& val) const{ val.Clear(); if ( IsSet(MSG_VIEWED) ) val += '*'; if ( IsSet(MSG_PARTIAL) ) val += 'm'; else if ( IsSet(MSG_MIME) ) val += 'M'; if ( IsSet(MSG_NEW) ) val += 'N'; else if ( !IsSet(MSG_READ) ) val += 'U'; if ( IsSet(MSG_DELETED) ) val += 'D'; if ( IsSet(MSG_SAVED) ) val += 'S'; if ( IsSet(MSG_REPLIED) ) val += '>'; if ( IsSet(MSG_FORWARDED) ) val += 'F'; if ( IsSet(MSG_RESENT) ) val += 'B'; if ( IsSet(MSG_PRINTED) ) val += 'P'; if ( IsSet(MSG_FILTERED) ) val += '|';} // End GetStatusString/*------------------------------------------------------------------------ * Method to build address structure for a header */AddressC*MsgC::AddressOf(const char *head) const{ HeaderC *data = Header(head); if ( !data ) return NULL; AddressC *addr = new AddressC(data->value->full); return addr;}/*------------------------------------------------------------------------ * Method to return text of subject header */voidMsgC::GetSubjectText(StringC& substr) const{ substr.Clear(); HeaderValC *sub = Subject(); if ( sub ) sub->GetValueText(substr); else substr = "[No subject]";}/*--------------------------------------------------------------- * Header query */HeaderC* MsgC::Headers() const { return body->headers; }HeaderC* MsgC::Header(CharC key) const { return body->Header(key); }HeaderValC* MsgC::HeaderValue(CharC key) const { return body->HeaderValue(key); }u_int MsgC::HeadOffset() { return body->offset; }int MsgC::HeadBytes() { return body->headBytes; }int MsgC::HeadLines() { return body->headLines; }/*--------------------------------------------------------------- * Methods to return the size of the body */intMsgC::BodyBytes(){ //if ( !bodySizeKnown ) ScanBody(); if ( !bodySizeKnown && body->bodyBytes < 0 ) ScanBody(); return body->bodyBytes;}intMsgC::BodyLines(){ // // It's so painfully slow to scan all messages just to count // the body line, the function is disabled. // if (folder->IsImap()) return 0; //if ( !bodySizeKnown ) ScanBody(); if ( !bodySizeKnown && body->bodyLines < 0 ) ScanBody(); return body->bodyLines;}/*--------------------------------------------------------------- * Method to return a pointer to the body structure */MsgPartC*MsgC::Body(){ if ( !body->bodyScanned ) ScanBody(); return body;}/*--------------------------------------------------------------- * Method to return the offset to the start of the body */u_intMsgC::BodyOffset(){ return body->bodyOffset;}/*--------------------------------------------------------------- * Method to return a pointer to the specified body part */MsgPartC*MsgC::Part(CharC partNum){ if ( !body->bodyScanned ) ScanBody(); return body->FindPart(partNum);}/*--------------------------------------------------------------- * Method to replace any header variables in the given string with * their value. */voidMsgC::ReplaceHeaders(StringC& str){//// Loop through string, substituting for header variables.// CharC key; StringC valStr; int pos; u_int off = 0; while ( (pos=str.PosOf('%', off)) >= 0 ) {//// Replace %% with %// if ( str[pos+1] == '%' ) { str(pos+1,0) = ""; off = pos+1; }//// Replace %header with value// else {//// Look for next non-alphanum// int len = 0; char c = str[pos+1]; while ( !isspace(c) && (isalnum(c) || c == '-') ) { len++; c = str[pos+1+len]; } key = str.Range(pos+1, len); valStr.Clear();//// Look up value for header// if ( key.Length() > 0 ) {//// Check for special cases// if ( key.Equals("fromname", IGNORE_CASE) ) { if ( from ) { if ( from->name ) from->name->GetValueText(valStr); else valStr = from->addr; } else valStr = "Unknown"; } else if ( key.Equals("fromaddr", IGNORE_CASE) ) { if ( from ) valStr = from->addr; else valStr = "Unknown"; }//// Look up value// else { HeaderValC *val = HeaderValue(key); if ( val ) val->GetValueText(valStr); else valStr = "Unknown"; }//// Escape '<'s since this string will be used in enriched text//
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -