1 现象:问题描述
在测试点到Email支持Logo功能时,配置为:支持Logo功能,Logo文件名是logo.txt,Logo媒体类型是 text/plain;向OutLook发送邮件。用OutLook查看邮件,发现Logo文件显示为正文,但是显示的是乱码且内容很少。更改配置为:支持Logo功能,Logo文件名是 logo.jpeg,Logo媒体类型是image/jpeg;用OutLook查看邮件,发现Logo文件显示为附件,打开附件却看不到图片。
2 关键过程:根本原因分析
根据现象分析,造成这一问题,可能的原因有三点:一是,邮件客户端的问题,Logo文件正确传入,但它不能对Logo文件进行正确的解码,进而文本显示乱码,图片不能预览;二是,系统初始化时,初始化Logo文件出错;三是,初始化Logo文件正确,但在后续处理中(向Email发消息前)出错。
第一个原因,查看邮件客户端OutLook配置的字符集,发现包含程序中编码的字符集SysNativeCharSet = 'utf-8' ,看来不是这个原因。
第二个原因,Logo文件初始化失败。对于Logo文件初始化失败的处理代码如下:
SMTP_RESULT CSmtpAgentCfgMgr::initDb(CSmtpDbAccess *pSmtpDbAccess)
{
ret = InitLogoMsg();
//Logo文件初始化失败,则返回失败标志
if(ret != SUCCESS)
{
setFailReason("InitLogoMsg failed\n");
return ret;
}
}
//Db初始化失败,则MM3Client模块启动失败
if (m_pSmtpAgentCfgMgr->initDb(m_pSmtpDbAccess) != SUCCESS)
{
SMTPTRACE(FL, NULL, SMTP_INIT_ERROR, "CSmtpAppManager", "Init SmtpAgentCfgMgr failed!");
m_pSmtpDbAccess->disConnect();
return -1;
}
可见,Logo文件初始化失败,MM3Client模块将不能启动。但是,在测试的时候,MM3Client模块能够正常启动,说明Logo文件初始化成功,看来也不是这个原因。
只有第三个原因了。用dbx跟踪MM3Client模块,查看程序运行的实际情况。先跟踪InitLogoMsg(),返回成功;跟踪AddLogoMsg(),返回成功。看来在流程上没有出错。进一步跟踪到函数InitLogoMsg()里面,看看读取的文件是否和配置的文件一样大。
char strLogoMsg[EMAIL_LOGO_MSG_LEN+1];
**********
m_iLogoMsgLen = read(fileNo, strLogoMsg, EMAIL_LOGO_MSG_LEN);
m_strLogoMsg = strLogoMsg; // m_strLogoMsg 是string类型的全局变量
***********
打印m_iLogoMsgLen,m_iLogoMsgLen = 7570,与配置的logo文件一样大。
跟踪到函数AddLogoMsg()里面,看看传入的文件数据有没有出错。
MMS_UINT32 iMsgLen = strlen(m_strLogoMsg.c_str());
打印 iMsgLen,iMsgLen = 4u
问题出现了,传入的数据远小于7570。这样的话,发送出去的logo文件几乎就是空的了。但是在初始化logo文件时,读取的大小是没有错的,问题就在后面的赋值语句了m_strLogoMsg = strLogoMsg。看来,传给m_strLogoMsg的数据只是strLogoMsg的很小一部分。
一般情况下,char类型数组是可以直接赋值给string类型变量的。
char strarray[] = "asdfgh";
string str;
str = strarray;
但是当char数组存储的是文件内容时,情况就不一样了。如:
read(fileNo, strLogoMsg, EMAIL_LOGO_MSG_LEN);
因为文件内是很可能含有'\0'的。这样数组里就可能有很多处的'\0',而char数组是以'\0'作为结束符号的。在做m_strLogoMsg = strLogoMsg这样的赋值操作时,实际上传给m_strLogoMsg只是char数组strLogoMsg第一个'\0'前的内容,而不是strLogoMsg的完整内容。如果strLogoMsg的第一位就是'\0'(这完全有可能),那么m_strLogoMsg就是空的。同时,strlen()返回的字符串大小也是不对的。这也就解释了测试时出现的问题了。
3 结论:解决方案及效果
我们可以做如下修改,来实现初始化logo文件和加载logo标志。
1. 初始化logo文件。更改全局变量string类型m_strLogoMsg为全局变量char数组m_strLogoMsg[EMAIL_LOGO_MSG_LEN+1],增加全局变量m_iLogoMsgLen表示logo大小。增加获取这些变量的接口函数getSmtpEmailLogoBuf(),getSmtpEmailLogoBufLen()等。
char* getSmtpEmailLogoBuf();
MMS_UINT32 getSmtpEmailLogoBufLen();
m_iLogoMsgLen = read(fileNo, strLogoMsg, EMAIL_LOGO_MSG_LEN);
2. 加载logo标志。Logo大小通过接口函数获得全局变量m_iLogoMsgLen值。
MMS_UINT32 iMsgLen = getSmtpEmailLogoBufLen();
std::string Temp64String = m_MM4Coder.GetBase64String((BYTE*)pTmpLogoBuf,&ReadPointer, iMsgLen);
验证以后,可以正常显示文本和图片。
4 经验总结:预防措施和规范建议
在开发过程中,我们在遇到像存储文件内容这样的操作时,尤其是存储内容为字节流时,还是使用数组来的好,建议只对内存操作,避免对字符串操作,防止无形中造成数据丢失。
5 备注
6 考核点
字符数组 字符串
阅读(449) | 评论(0) | 转发(0) |