📄 imapmsgc.c
字号:
/* * $Id: ImapMsgC.C,v 1.6 2000/12/31 14:36: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 "ImapMsgC.h"#include "ImapFolderC.h"#include "ImapServerC.h"#include "MsgPartC.h"#include "IshAppC.h"#include "MsgItemC.h"#include "HeaderC.h"#include <hgl/StringC.h>#include <hgl/SysErr.h>#include <errno.h>#include <unistd.h>/*--------------------------------------------------------------- * Constructor */ImapMsgC::ImapMsgC(ImapFolderC *fld, ImapServerC *serv, int num) : MsgC(fld){ type = IMAP_MSG; server = serv; number = num; folder = fld; ScanHead();}/*--------------------------------------------------------------- * Destructor */ImapMsgC::~ImapMsgC(){}/*--------------------------------------------------------------- * Methods to return the header text */BooleanImapMsgC::GetHeaderText(StringC& str) const{ char *text; char *flags; StringC response; if ( !server->FetchHdrs(number, folder, &body->bytes, &text, &flags, response) ) return False; delete flags;//// Remove the last blank line if present// str += text; if ( str.EndsWith("\n\n") ) str.CutEnd(1); delete text; return True;} // End GetHeaderTextBooleanImapMsgC::GetHeaderText(StringC& str){ char *text; char *flags; StringC response; if ( !server->FetchHdrs(number, folder, &body->bytes, &text, &flags, response) ) return False; if ( flags ) ParseFlags(flags); delete flags;//// Remove the last blank line if present// str += text; if ( str.EndsWith("\n\n") ) str.CutEnd(1); delete text; return True;} // End GetHeaderText/*--------------------------------------------------------------- * Methods to return the body text */BooleanImapMsgC::GetBodyText(StringC& str) const{ char *text; char *flags; StringC response; if ( !server->Fetch(number, folder, "RFC822.TEXT", &text, &flags, response) ) return False; delete flags; str += text; delete text; return True;} // End GetBodyTextBooleanImapMsgC::GetBodyText(StringC& str){ char *text = NULL; char *flags = NULL; StringC response; if ( !server->Fetch(number, folder, "RFC822.TEXT", &text, &flags, response) ) return False;//// Remove closing parenthesis from the FETCH results// // XXX - FIXME for some reason, text can be NULL here if (!text) { cerr << "ERROR!! text is NULL at " << __FILE__ << ":" << __LINE__ << "\n"; return False; } int pos = strlen(text) - 1; if (text[pos] == '\n' && text[pos-1] == ')' && text[pos-2] == '\n' ) text[pos-1] = '\0'; if ( strlen(text) != body->bodyBytes ) { if ( debuglev > 0 && body->bodyBytes >= 0 ) cout <<"We thought body was " <<body->bodyBytes <<" bytes but we got " <<strlen(text) <<" bytes" <<endl; CharC textStr(text); body->bodyBytes = textStr.Length(); body->bodyLines = textStr.NumberOf('\n'); body->ComputeSize(); } if ( flags ) ParseFlags(flags); delete flags; str += text; delete text; return True;} // End GetBodyText/*--------------------------------------------------------------- * Methods to return the body text for the specified part */BooleanImapMsgC::GetPartText(const MsgPartC *part, StringC& str, Boolean getHead, Boolean getExtHead, Boolean getBody) const{ char *text = NULL; char *flags = NULL; StringC response; StringC cmd;//// Get the headers if necessary// if ( getHead ) { cmd = "BODY["; cmd += part->partNum; cmd += ".0]"; if ( !server->Fetch(number, folder, cmd, &text, &flags, response) ) return False; str += text; str += '\n'; delete text; delete flags; } text = NULL; flags = NULL; cmd = "BODY["; cmd += part->partNum; cmd += "]"; if ( !server->Fetch(number, folder, cmd, &text, &flags, response) ) return False;//// Remove closing parenthesis from the FETCH results// int pos = strlen(text) - 1; if (text[pos] == '\n' && text[pos-1] == ')' && text[pos-2] == '\n' ) text[pos-1] = '\0';//// See if the external headers need to be stripped or extracted// CharC textStr = text; if ( part->IsExternal() && (!getExtHead || !getBody) ) { int blankPos = textStr.PosOf("\n\n"); if ( getExtHead ) { if ( blankPos >= 0 ) textStr.CutEnd(textStr.Length()-blankPos+1); } else { // getBody if ( blankPos >= 0 ) textStr.CutBeg(blankPos+2); } } str += textStr; delete text; delete flags; return True;} // End GetPartText/*--------------------------------------------------------------- * Method to return the body text for the specified part that can * be called by non-const objects */BooleanImapMsgC::GetPartText(const MsgPartC *part, StringC& str, Boolean getHead, Boolean getExtHead, Boolean getBody){ char *text = NULL; char *flags = NULL; StringC response; StringC cmd;//// Get the headers if necessary// if ( getHead ) { cmd = "BODY["; cmd += part->partNum; cmd += ".0]"; if ( !server->Fetch(number, folder, cmd, &text, &flags, response) ) return False; str += text; str += '\n'; delete text; if ( flags ) ParseFlags(flags); delete flags; } // End if headers requested text = NULL; flags = NULL; const StringC& num = part->partNum; cmd = "BODY["; cmd += num; cmd += "]"; if ( !server->Fetch(number, folder, cmd, &text, &flags, response) ) return False;//// Double check body size// CharC bodyStr = text; int blankPos = bodyStr.PosOf("\n\n"); if ( blankPos >= 0 ) bodyStr.CutBeg(blankPos+2); if ( bodyStr.Length() != part->bodyBytes ) { if ( debuglev > 0 && part->bodyBytes >= 0 ) cout <<"We thought part was " <<part->bodyBytes <<" bytes but we got " <<bodyStr.Length() <<" bytes" <<endl; MsgPartC *tmp = (MsgPartC*)part; tmp->bodyBytes = bodyStr.Length(); tmp->bodyLines = bodyStr.NumberOf('\n'); tmp->ComputeSize(); }//// See if the external headers need to be stripped or extracted// CharC textStr = text; if ( part->IsExternal() && (!getExtHead || !getBody) ) { if ( getExtHead ) { blankPos = textStr.PosOf("\n\n"); if ( blankPos >= 0 ) textStr.CutEnd(textStr.Length()-blankPos+1); } else { // getBody textStr = bodyStr; } } if ( flags ) ParseFlags(flags); delete flags; str += textStr; delete text; return True;} // End GetPartText/*--------------------------------------------------------------- * Methods to return the decoded contents of this body part */BooleanImapMsgC::GetFileData(MsgPartC *part, StringC& text) const{ return part->GetData(text);}BooleanImapMsgC::GetFileData(MsgPartC *part, StringC& text){ return part->GetData(text);}/*--------------------------------------------------------------- * Method to scan the file and determine the header sizes and body byte count */voidImapMsgC::ScanHead(){ StringC headers; if ( !GetHeaderText(headers) ) return;//// Read the headers// body->headLines = 0; body->headBytes = headers.size(); StringC headStr; u_int offset = 0; int nlPos = headers.PosOf('\n', offset); while ( nlPos >= 0 ) { body->headLines++; int len = nlPos - offset + 1;//// Check for a continuation// if ( isspace(headers[offset]) ) headStr += headers(offset, len); else { if ( headStr.size() > 0 ) body->AddHeader(headStr); headStr = headers(offset, len); } offset = nlPos+1; nlPos = headers.PosOf('\n', offset); } // End for each header line//// We don't have to read another line because the header text is guaranteed// to end with a newline////// See if we have a final header// if ( headStr.size() > 0 ) body->AddHeader(headStr);//// Check for special headers// HeaderC *head = body->headers; while ( head ) { CheckHeader(head); head = head->next; } body->SetPartNumber("1");//// If this is an external part, read the external headers// if ( body->IsExternal() ) GetExternalInfo(body);//// Get body size// body->bodyBytes = body->bytes; if ( body->headBytes > 0 ) body->bodyBytes -= (body->headBytes + 1); if ( body->extBytes > 0 ) body->bodyBytes -= (body->extBytes + 1);//// See if we found a content-type header// body->defConType = (body->conStr.size() == 0); if ( body->defConType ) { if ( body->parent && body->parent->IsDigest() ) body->SetType("message/rfc822"); else body->SetType("text/plain"); }//// Don't mark plain text as MIME// if ( IsMime() && body->IsPlainText() && !body->IsEncoded() && !body->IsAttachment() && !body->IsExternal() ) ClearStatus(MSG_MIME, False); ClearStatus(MSG_CHANGED, False); body->headScanned = True;} // End ScanHead/*--------------------------------------------------------------- * Method to scan the file and determine the body structure */voidImapMsgC::ScanBody(){ if ( debuglev > 1 ) cout <<"Scanning body in message " <<number <<endl; char *text; char *flags; StringC response;//// If the top-level part is an external body, we already know the structure// We'll just count the number of lines in the body.// if ( body->IsExternal() ) {//// Get body text// if ( !server->Fetch(number, folder, "RFC822.TEXT", &text, &flags, response) ) return;//// Remove everything up to and including the first blank line// CharC bodyStr = text; int blankPos = bodyStr.PosOf("\n\n"); if ( blankPos >= 0 ) bodyStr.CutBeg(blankPos+2); body->bodyLines = bodyStr.NumberOf('\n'); } // End if body is external//// We need the structure// else { if ( !server->Fetch(number, folder, "BODY", &text, &flags, response) ) return; if ( flags ) ParseFlags(flags); delete flags; body->bodyLines = 0; ScanPart(text, body); delete text; body->SetPartNumber("1"); body->SetPartNumberSize(body->GetPartNumberMaxSize());//// Now we need to traverse the tree and get more information about any// external parts. This has to be done after the part numbers are// calculated.// GetExternalInfo(body); } // End if top-level part is not external body->bodyScanned = True; bodySizeKnown = True;} // End ScanBody/*--------------------------------------------------------------- * Method to parse a body string * * body : multipart-body or msg-body or other-body * multipart-body: (part) (part) ... (part) type * message-body : type subtype (params) id {len} desc enc bytes (envelope) (body) lines * other-body : type subtype (params) {len} id {len} desc enc bytes * params : (key {len} val) (key {len} val) ... (key {len} val) * envelope : {len} date {len} subj (addr:from) (addr:sender) (addr:reply-to) (addr:to) (addr:cc) (addr:bcc) {len} in-reply-to {len} message-id * addr : name route mailbox host * */char*ImapMsgC::ScanPart(char *data, MsgPartC *part){//// Skip initial whitespace// char *cp = data; while ( isspace(*cp) ) cp++; if ( *cp != '(' ) { cerr <<"Syntax error. Expecting body part: "<<cp <<endl; return cp; } cp++;//// Scan to corresponding right paren// StringC headStr; Boolean done = False; while ( !done && *cp ) { while ( isspace(*cp) ) cp++;//// See if this part is a multipart// if ( *cp == '(' ) { if ( !part->IsMultipart() ) part->SetType("multipart/mixed"); MsgPartC *newPart = new MsgPartC(part); newPart->parentMsg = this; if ( !part->child ) { if ( debuglev > 1 ) cout <<"Creating first child in multipart" <<endl; part->child = newPart; } else { if ( debuglev > 1 ) cout <<"Creating another child in multipart" <<endl; MsgPartC *lastPart = part->child; while ( lastPart->next ) lastPart = lastPart->next; lastPart->next = newPart; newPart->prev = lastPart; } cp = ScanPart(cp, newPart); }//// See if this is the end of this part// else if ( *cp == ')' ) { done = True; cp++; }//// If we're in a multipart, this must be the type// else if ( part->IsMultipart() ) { CharC text; cp = ScanText(cp, text); StringC type = "multipart/"; type += text; part->SetType(type); }//// Scan the info for this part// else { CharC group; CharC subtype; cp = ScanText(cp, group); cp = ScanText(cp, subtype); StringC type; if ( group.Length() > 0 ) type = group; else type = "text"; type += '/'; type.toLower(); if ( subtype.Length() > 0 ) type += subtype; else if ( type.Equals("text/") ) type += "plain"; else if ( type.Equals("image/") ) type += "gif"; else if ( type.Equals("audio/") ) type += "basic"; else if ( type.Equals("video/") ) type += "mpeg"; else if ( type.Equals("message/") ) type += "rfc822"; else if ( type.Equals("application/") ) type += "octet-stream"; else type += "x-unknown"; type.toLower(); cp = ScanParams(cp, type); part->SetType(type);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -