Windows2003-3790/inetcore/outlookexpress/wabw/vcard/versit/2.0/vcdoc.cpp
2020-09-30 16:53:55 +02:00

708 lines
21 KiB
C++

/***************************************************************************
(C) Copyright 1996 Apple Computer, Inc., AT&T Corp., International
Business Machines Corporation and Siemens Rolm Communications Inc.
For purposes of this license notice, the term Licensors shall mean,
collectively, Apple Computer, Inc., AT&T Corp., International
Business Machines Corporation and Siemens Rolm Communications Inc.
The term Licensor shall mean any of the Licensors.
Subject to acceptance of the following conditions, permission is hereby
granted by Licensors without the need for written agreement and without
license or royalty fees, to use, copy, modify and distribute this
software for any purpose.
The above copyright notice and the following four paragraphs must be
reproduced in all copies of this software and any software including
this software.
THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS AND NO LICENSOR SHALL HAVE
ANY OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS OR
MODIFICATIONS.
IN NO EVENT SHALL ANY LICENSOR BE LIABLE TO ANY PARTY FOR DIRECT,
INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES OR LOST PROFITS ARISING OUT
OF THE USE OF THIS SOFTWARE EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
DAMAGE.
EACH LICENSOR SPECIFICALLY DISCLAIMS ANY WARRANTIES, EXPRESS OR IMPLIED,
INCLUDING BUT NOT LIMITED TO ANY WARRANTY OF NONINFRINGEMENT OR THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE.
The software is provided with RESTRICTED RIGHTS. Use, duplication, or
disclosure by the government are subject to restrictions set forth in
DFARS 252.227-7013 or 48 CFR 52.227-19, as applicable.
***************************************************************************/
// VCdoc.cpp : implementation of the CVCDoc class
#include "stdafx.h"
#include "VC.h"
#include <strstrea.h>
#include "VCdoc.h"
#include "vcard.h"
#include "clist.h"
#include "gifread.h"
#include "mainfrm.h"
#include "msv.h"
#include "mime.h"
#ifdef _DEBUG
#undef THIS_FILE
static char BASED_CODE THIS_FILE[] = __FILE__;
#endif
//#define TRY_CFILE
#define smPt 14
#define bgPt 16
CM_CFUNCTIONS
#if 0
extern BOOL Parse_HTML(
const char *input, /* In */
int len, /* In */
const char *dirPath, /* In */
CVCard **card, /* Out */
int *_posPreambleEnd, /* Out */
int *_posPostambleStart, /* Out */
char **_unknownTags); /* Out */
#endif
CM_END_CFUNCTIONS
CString CanonicalPath(const CString &path);
CString NativePath(const CString &path);
/////////////////////////////////////////////////////////////////////////////
// CVCDoc
IMPLEMENT_DYNCREATE(CVCDoc, CDocument)
BEGIN_MESSAGE_MAP(CVCDoc, CDocument)
//{{AFX_MSG_MAP(CVCDoc)
ON_COMMAND(ID_INSERT_LOGO, OnInsertLogo)
ON_COMMAND(ID_INSERT_PHOTO, OnInsertPhoto)
ON_COMMAND(ID_INSERT_PRONUN, OnInsertPronun)
ON_COMMAND(ID_SEND_IRDA, OnSendIrda)
ON_UPDATE_COMMAND_UI(ID_SEND_IRDA, OnUpdateSendIrda)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CVCDoc construction/destruction
/////////////////////////////////////////////////////////////////////////////
CVCDoc::CVCDoc()
{
// TODO: add one-time construction code here
m_sizeDoc = CSize(8192, 5000);
m_minSizeDoc = CSize(8192, 5000);
m_vcard = NULL;
m_preamble = m_postamble = NULL;
m_preambleLen = m_postambleLen = 0;
m_unknownTags = NULL;
}
/////////////////////////////////////////////////////////////////////////////
CVCDoc::~CVCDoc()
{
if (m_vcard) delete m_vcard;
if (m_preamble) delete [] m_preamble;
if (m_postamble) delete [] m_postamble;
if (m_unknownTags) delete m_unknownTags;
}
/////////////////////////////////////////////////////////////////////////////
BOOL CVCDoc::OnNewDocument()
{
if (!CDocument::OnNewDocument())
return FALSE;
// TODO: add reinitialization code here
// (SDI documents will reuse this document)
CVCNode *root, *english;
if (m_vcard)
delete m_vcard;
m_vcard = new CVCard;
m_vcard->AddObject(root = new CVCNode); // create root
root->AddProp(new CVCProp(VCRootObject)); // mark it so
english = root->AddObjectProp(vcBodyProp, VCBodyObject);
return TRUE;
}
/////////////////////////////////////////////////////////////////////////////
// CVCDoc serialization
void CVCDoc::Serialize(CArchive& ar)
{
if (ar.IsStoring())
{
// TODO: add storing code here
ar << m_sizeDoc;
}
else
{
// TODO: add loading code here
ar >> m_sizeDoc;
}
// Calling the base class CDocument enables serialization
// of the container document's COleClientItem objects.
CDocument::Serialize(ar);
}
/////////////////////////////////////////////////////////////////////////////
// CVCDoc diagnostics
#ifdef _DEBUG
void CVCDoc::AssertValid() const
{
CDocument::AssertValid();
}
void CVCDoc::Dump(CDumpContext& dc) const
{
CDocument::Dump(dc);
}
#endif //_DEBUG
/////////////////////////////////////////////////////////////////////////////
// CVCDoc commands
CString CVCDoc::PathToAuxFile(const char *auxPath)
{
CString directory = GetPathName(), path;
int slash = directory.ReverseFind('\\');
CString auxStr(auxPath);
if (slash == -1)
directory = "";
else
directory = directory.Left(slash);
path = (auxStr[0] == '/') ? NativePath(auxStr) : (directory + "\\" + NativePath(auxStr));
return path;
}
/////////////////////////////////////////////////////////////////////////////
CString PathSansVolume(const CString &path)
{
CString result;
if (path.Find(':') == 1) // strip the volume name
result = path.Right(path.GetLength() - 2);
else if ((path.GetLength() > 2) && (path.Left(2) == "\\\\")) {
// a path like \\Host\path
int slash;
result = path.Right(path.GetLength() - 2);
VERIFY((slash = result.Find('\\')) != -1);
result = result.Right(result.GetLength() - slash);
} else
result = path;
return result;
}
HGLOBAL CVCDoc::ReadFileIntoMemory(const char *path, int *inputLen)
{
fpos_t inLength;
FILE *inputFile;
U8 *buf = NULL;
inputFile = fopen(path, "rb");
if (!inputFile)
goto Error;
fseek(inputFile, 0, SEEK_END);
fgetpos(inputFile, &inLength);
fseek(inputFile, 0, SEEK_SET);
if (!(buf = (U8 *)GlobalAlloc(0, (long)inLength)))
goto Error;
if (fread(buf, 1, (long)inLength, inputFile) < (unsigned)inLength)
goto Error;
*inputLen = (int)inLength;
goto Done;
Error:
if (buf) { GlobalFree(buf); buf = NULL; }
Done:
if (inputFile)
fclose(inputFile);
return buf;
}
/////////////////////////////////////////////////////////////////////////////
// This sets some estimated display locations for some string properties.
// The final locations can be determined only after all the properties have
// been added to the body, and that is done by AdjustDisplayLocations().
VC_DISPTEXT *DisplayInfoForProp(const char *name, VC_DISPTEXT *info)
{
//CClientDC dc(AfxGetApp()->m_pMainWnd);
//dc.AssertValid();
//int ppi = GetDeviceCaps(dc.m_hDC, LOGPIXELSY);
memset(info, 0, sizeof(*info));
info->typeSize = smPt;
info->textAlign = VC_LEFT;
info->textClass = VC_MODERN;
/**** middle right group ****/
if (strcmp(name, vcFullNameProp) == 0) {
info->x = 4200;
info->y = 2500 + (smPt * 3) * 20;
} else if (strcmp(name, vcTitleProp) == 0) {
info->x = 4200;
info->y = 2500 + (smPt * 2) * 20;
info->textAttrs = VC_ITALIC;
} else
/**** lower right group ****/
if (strcmp(name, vcTelephoneProp) == 0) {
info->x = 4200;
info->y = 300 + (10 * 2) * 20;
info->typeSize = 10;
} else if (strcmp(name, vcEmailAddressProp) == 0) {
info->x = 4200;
info->y = 300 + (10 * 1) * 20;
info->typeSize = 10;
} else
/**** upper left group ****/
if (strcmp(name, vcOrgNameProp) == 0) {
info->x = 300;
info->y = 5000 - 300;
info->typeSize = bgPt;
} else
/**** middle left group ****/
if (strcmp(name, vcOrgUnitProp) == 0) {
info->x = 300;
info->y = 2500 + (smPt * 3) * 20;
} else if (strcmp(name, vcDeliveryLabelProp) == 0) {
info->x = 300;
info->y = 2500 + (smPt * 2) * 20;
}
return info->x ? info : NULL;
}
/////////////////////////////////////////////////////////////////////////////
// This is called as a final step in the parsing, after the entire body has
// been built. Now that all the properties and their estimated locations are
// there, some final tweaking can be done.
void AdjustDisplayLocations(CVCNode *body)
{
CVCPropEnumerator *enumerator;
CVCProp *prop;
VC_DISPGIF *gifInfo = NULL;
// is there a logo?
enumerator = new CVCPropEnumerator(body);
while ((prop = enumerator->NextProp())) {
if (strcmp(prop->GetName(), vcLogoProp) == 0) {
CVCValue *value = prop->FindValue(VCDisplayInfoGIFType);
if (value) {
gifInfo = (VC_DISPGIF *)value->GetValue();
if (gifInfo->top < 1700) {
VC_DISPGIF dt;
int h = gifInfo->top - gifInfo->bottom;
dt = *gifInfo;
dt.top = 1700;
dt.bottom = dt.top - h;
value->SetValue(&dt, sizeof(dt));
gifInfo = (VC_DISPGIF *)value->GetValue();
}
}
break;
}
} // while
delete enumerator;
if (!gifInfo)
return;
// if have a logo, move middle right group (name, title) so that its top
// is aligned with the top of the logo and adjust the top of the photo, if any
enumerator = new CVCPropEnumerator(body);
while ((prop = enumerator->NextProp())) {
if (strcmp(prop->GetName(), vcFullNameProp) == 0) {
VC_DISPTEXT *info = (VC_DISPTEXT *)prop->FindValue(VCDisplayInfoTextType)->GetValue();
info->y = gifInfo->top;
} else if (strcmp(prop->GetName(), vcTitleProp) == 0) {
VC_DISPTEXT *info = (VC_DISPTEXT *)prop->FindValue(VCDisplayInfoTextType)->GetValue();
info->y = gifInfo->top - smPt * 20;
} else if (strcmp(prop->GetName(), vcPhotoProp) == 0) {
CVCValue *value = prop->FindValue(VCDisplayInfoGIFType);
VC_DISPGIF *photoInfo;
int h;
if (!value) continue;
photoInfo = (VC_DISPGIF *)value->GetValue();
h = photoInfo->top - photoInfo->bottom;
photoInfo->bottom = gifInfo->top + smPt * 20;
photoInfo->top = photoInfo->bottom + h;
}
} // while
delete enumerator;
}
/////////////////////////////////////////////////////////////////////////////
void CVCDoc::SetDisplayInfo(CVCNode *body, const char *docPath)
{
CVCPropEnumerator enumerator(body);
CVCProp *prop;
CString directory(docPath);
int slash = directory.ReverseFind('\\');
BOOL hasMask;
FCOORD size;
CGifReader gifRdr;
if (slash == -1)
directory = "";
else
directory = directory.Left(slash);
while ((prop = enumerator.NextProp())) {
const char *propName = prop->GetName();
if (strcmp(propName, vcPhotoProp) == 0) {
CVCValue *value = prop->FindValue(VCGIFType);
istrstream strm((char *)value->GetValue(), value->GetSize());
if (gifRdr.GetGifSize(&strm, &size, &hasMask)) {
/**** upper right group ****/
VC_DISPGIF gifInfo;
gifInfo.left = 4200;
gifInfo.right = gifInfo.left + (int)size.x * 20;
gifInfo.top = 5000 - 300;
gifInfo.bottom = gifInfo.top - (int)size.y * 20;
gifInfo.hasMask = hasMask;
prop->AddValue(new CVCValue(VCDisplayInfoGIFType, &gifInfo, sizeof(gifInfo)));
}
} else if (strcmp(propName, vcLogoProp) == 0) {
CVCValue *value = prop->FindValue(VCGIFType);
istrstream strm((char *)value->GetValue(), value->GetSize());
if (gifRdr.GetGifSize(&strm, &size, &hasMask)) {
/**** lower left group ****/
VC_DISPGIF gifInfo;
gifInfo.left = 300;
gifInfo.right = gifInfo.left + (int)size.x * 20;
gifInfo.top = 300 + (int)size.y * 20;
gifInfo.bottom = gifInfo.top - (int)size.y * 20;
gifInfo.hasMask = hasMask;
prop->AddValue(new CVCValue(VCDisplayInfoGIFType, &gifInfo, sizeof(gifInfo)));
}
} else {
VC_DISPTEXT dispText;
if (DisplayInfoForProp(propName, &dispText))
prop->AddValue(
new CVCValue(VCDisplayInfoTextType, &dispText, sizeof(dispText)));
}
}
AdjustDisplayLocations(body);
}
#ifdef TRY_CFILE
/////////////////////////////////////////////////////////////////////////////
BOOL CVCDoc::OnOpenDocument(LPCTSTR lpszPathName)
{
char *unknownTags = NULL;
BOOL doPrePostamble = FALSE;
CFile input(lpszPathName, CFile::modeRead | CFile::shareCompat);
CString directory(lpszPathName);
int slash = directory.ReverseFind('\\');
//if (!CDocument::OnOpenDocument(lpszPathName))
//return FALSE;
if (m_preamble) { delete [] m_preamble; m_preamble = NULL; }
if (m_postamble) { delete [] m_postamble; m_postamble = NULL; }
if (m_unknownTags) { delete m_unknownTags; m_unknownTags = NULL; }
m_preambleLen = m_postambleLen = 0;
if (slash == -1)
directory = "";
else
directory = directory.Left(slash);
if (Parse_MSV_FromFile(&input, &m_vcard)) {
} else if (Parse_MIME_FromFile(&input, &m_vcard)) {
} else
return FALSE;
SetDisplayInfo(m_vcard->FindBody(), lpszPathName);
if (unknownTags) {
if (strlen(unknownTags))
m_unknownTags = new CString(unknownTags);
delete [] unknownTags;
}
return TRUE;
}
#else
/////////////////////////////////////////////////////////////////////////////
BOOL CVCDoc::OnOpenDocument(LPCTSTR lpszPathName)
{
int posPreambleEnd, posPostambleStart;
char *unknownTags = NULL;
BOOL doPrePostamble = FALSE;
char *input = NULL;
int inputLen;
CString directory(lpszPathName);
int slash = directory.ReverseFind('\\');
//if (!CDocument::OnOpenDocument(lpszPathName))
//return FALSE;
if (!(input = (char *)ReadFileIntoMemory(lpszPathName, &inputLen)))
return FALSE;
if (m_preamble) { delete [] m_preamble; m_preamble = NULL; }
if (m_postamble) { delete [] m_postamble; m_postamble = NULL; }
if (m_unknownTags) { delete m_unknownTags; m_unknownTags = NULL; }
m_preambleLen = m_postambleLen = 0;
if (slash == -1)
directory = "";
else
directory = directory.Left(slash);
if (Parse_MSV(input, inputLen, &m_vcard)) {
} else if (Parse_MIME(input, inputLen, &m_vcard)) {
} else
return FALSE;
if (doPrePostamble) { // now read in and store the preamble and postamble
if ((m_preambleLen = posPreambleEnd)) {
m_preamble = new char[m_preambleLen];
memcpy(m_preamble, input, m_preambleLen);
}
if ((m_postambleLen = inputLen - posPostambleStart)) {
m_postamble = new char[m_postambleLen];
memcpy(m_postamble, input + posPostambleStart, m_postambleLen);
}
}
SetDisplayInfo(m_vcard->FindBody(), lpszPathName);
if (unknownTags) {
if (strlen(unknownTags))
m_unknownTags = new CString(unknownTags);
delete [] unknownTags;
}
if (input) GlobalFree(input);
return TRUE;
}
#endif
/////////////////////////////////////////////////////////////////////////////
BOOL CVCDoc::OnSaveDocument(LPCTSTR lpszPathName)
{
FILE *outputFile;
char *tempname;
BOOL error = FALSE;
//int len;
tempname = _tempnam(NULL, "CARD");
outputFile = fopen(tempname, "w+");
#if 0
if (m_preambleLen
&& (fwrite(m_preamble, 1, m_preambleLen, outputFile) < (unsigned)m_preambleLen)) {
error = TRUE;
goto Done;
}
#endif
if ((error = !m_vcard->Write(outputFile)))
goto Done;
#if 0
if (m_unknownTags && (len = m_unknownTags->GetLength())
&& (fwrite((const char *)*m_unknownTags, 1, len, outputFile) < (unsigned)len)) {
error = TRUE;
goto Done;
}
if (m_postambleLen
&& (fwrite(m_postamble, 1, m_postambleLen, outputFile) < (unsigned)m_postambleLen)) {
error = TRUE;
goto Done;
}
#endif
Done:
fclose(outputFile);
if (error) {
CString msg;
msg.Format("Could not write to file \"%s\":\n%s", tempname, strerror(errno));
AfxMessageBox(msg);
} else {
unlink(lpszPathName); // remove it if it's already there
rename(tempname, lpszPathName);
SetModifiedFlag(FALSE);
}
free(tempname);
return !error;
// return CDocument::OnSaveDocument(lpszPathName);
}
/////////////////////////////////////////////////////////////////////////////
CString CanonicalPath(const CString &path)
{
CString result(path);
int len = path.GetLength();
for (int i = 0; i < len; i++)
if (path[i] == '\\')
result.SetAt(i, '/');
return result;
}
/////////////////////////////////////////////////////////////////////////////
CString NativePath(const CString &path)
{
CString result(path);
int len = path.GetLength();
for (int i = 0; i < len; i++)
if (path[i] == '/')
result.SetAt(i, '\\');
return result;
}
/////////////////////////////////////////////////////////////////////////////
void CVCDoc::InsertFile(const char *propName, const char *theType, const char *path)
{
int size;
HGLOBAL contents = ReadFileIntoMemory(path, &size);
CVCNode *body = m_vcard->FindBody();
CVCPropEnumerator enumerator(body);
CVCProp *prop, *existing = NULL;
while ((prop = enumerator.NextProp()))
if (strcmp(prop->GetName(), propName) == 0) {
existing = prop;
break;
}
if (existing) {
BOOL didReplace = FALSE;
for (CLISTPOSITION pos = existing->GetValues()->GetHeadPosition(); pos; ) {
CVCValue *value = (CVCValue *)existing->GetValues()->GetNext(pos);
if (strcmp(value->GetType(), VCStrIdxType) == 0)
continue;
if (strcmp(value->GetType(), VCDisplayInfoGIFType) == 0) {
existing->RemoveValue(value);
continue;
}
if (strcmp(value->GetType(), theType) != 0)
value->SetType(theType);
value->SetValue(contents, size);
didReplace = TRUE;
}
if (!didReplace)
existing->AddValue(new CVCValue(theType, (void *)contents, size));
} else {
CVCNode *node = body->AddPart();
node->AddProp(new CVCProp(propName, theType, (void *)contents, size));
node->AddBoolProp(vcBase64Prop);
node->AddBoolProp((strcmp(theType, vcGIFType) == 0) ? vcGIFProp : vcWAVEProp);
}
GlobalFree(contents);
SetDisplayInfo(body, GetPathName());
SetModifiedFlag();
UpdateAllViews(NULL);
}
/////////////////////////////////////////////////////////////////////////////
void CVCDoc::OnInsertLogo()
{
CFileDialog dialog(
TRUE, NULL, NULL, 0,
"Image Files (*.gif) | *.gif; | All Files (*.*) | *.* ||");
if (dialog.DoModal() == IDOK) {
CString ext(dialog.GetFileExt());
InsertFile(vcLogoProp, VCGIFType, dialog.GetPathName());
}
}
/////////////////////////////////////////////////////////////////////////////
void CVCDoc::OnInsertPhoto()
{
CFileDialog dialog(
TRUE, NULL, NULL, 0,
"Image Files (*.gif;) | *.gif; | All Files (*.*) | *.* ||");
if (dialog.DoModal() == IDOK) {
CString ext(dialog.GetFileExt());
InsertFile(vcPhotoProp, VCGIFType, dialog.GetPathName());
}
}
/////////////////////////////////////////////////////////////////////////////
void CVCDoc::OnInsertPronun()
{
CFileDialog dialog(
TRUE, NULL, NULL, 0,
"Wave Files (*.wav) | *.wav | All Files (*.*) | *.* ||");
if (dialog.DoModal() == IDOK) {
InsertFile(vcPronunciationProp, VCWAVType, dialog.GetPathName());
}
}
/////////////////////////////////////////////////////////////////////////////
void CVCDoc::OnSendIrda()
{
char *tempname;
BOOL savedFlag = IsModified();
CString path(GetPathName()), directory, name;
CVCNode *body = m_vcard->FindBody();
CVCApp *app = (CVCApp *)AfxGetApp();
if (!app->CanSendFileViaIR())
return;
// save the card file to a temporary location
tempname = _tempnam(NULL, "CARD");
OnSaveDocument(tempname);
SetModifiedFlag(savedFlag);
{ // get the directory containing the card file
int slash = path.ReverseFind('\\');
if (slash == -1) {
directory = "";
name = path;
} else {
directory = CanonicalPath(PathSansVolume(path.Left(slash)));
name = path.Right(path.GetLength() - slash - 1);
}
}
// now send the card file
app->SendFileViaIR(tempname, name, TRUE);
// and remove the temporary card file
unlink(tempname);
free(tempname);
}
/////////////////////////////////////////////////////////////////////////////
void CVCDoc::OnUpdateSendIrda(CCmdUI* pCmdUI)
{
CVCApp *app = (CVCApp *)AfxGetApp();
pCmdUI->Enable(app->CanSendFileViaIR());
}