免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 2448 | 回复: 4

2005年毕业设计时写的一个小程序,共享。 [复制链接]

论坛徽章:
0
发表于 2009-04-14 14:14 |显示全部楼层
该程序主要完成电子邮件中邮件附件的编码与解码工作。其中对BASE64编码原理的理解还是比较完善的。如果以后有人用到这些东西,可以参考。
#include<stdio.h>
#include<stdlib.h>
#include"string"
//***********************************************************
unsigned short Chr2Base( char c );
int B64Decode( FILE *fpoutfile, FILE *fpinfile,int n );
int counter(FILE *in_file);
void convertmain(char adrin[20]/*要处理的本地临时文件地址*/);
//***********************************************************
int checkct(char fin[100],int n);
int checkfi(char fin[100],int n);
int strcount(char fstr[100]);
void filecopy(FILE *fp,char adr[20]);
int linecount(FILE *fpinfile);
void checkmain(FILE *fpinfile,char adr[20],int line);
//***********************************************************
void main()
{
        printf("此程序是对基于foxmail客户端的文本格式邮件导出的.eml文件进行分析、提取和解码:\n");
        FILE *fpinfile;
        int n;
        char adr[20];
        printf("输入要处理的文件:\n");
        scanf("%s",adr);
        fpinfile=fopen(adr,"r");
        if(fpinfile==NULL)
        {
                printf("can't open the file,please check your URL\n");
            return;
        }
        n=linecount(fpinfile);
        fpinfile=fopen(adr,"r");
//        printf("%d\n",n);
        checkmain(fpinfile,adr,n);
}

//—————————————————————————————————————————
//**********************************************************************************
//—————————————————————————————————————————

int linecount(FILE *fpinfile)//计算要处理文件的行数,以便后边处理
{
        int count=0;
        int ch;
            while(1)
                {
                ch=fgetc(fpinfile);
                if(ch==EOF)
                        break;
                ++count;

                }
        return int(count/50);
        fclose(fpinfile);
}

void checkmain(FILE *fpinfile,char adr[20],int line)
{  
        char fstr[100];        //行缓冲数组
        int n;                 //行缓冲数组中有效字符长度     
        int m=0;               //用来标记 Content-Type的出现次数
        char adrtemp[20];      //存储临时文件地址
        for(int i=0;i<line/*入口参数*/;i++)
        {
        fgets(fstr,100,fpinfile);
        n=strcount(fstr);
//        checkct(fstr, n);//找content-type
                if( checkct(fstr, n)==1)//第一个content-type将不参与处理
                {
                        m=m+1;
                }
                else          
                        checkfi(fstr,n);//找filename
//***                printf("coming   !!!!!\n");
                //对吗?原本想只对第二个以后的content-type进行处理
                if((m>1)&&(fstr[0]=='\n'))//第一个content-type将不参与处理   
                {   
//***                        printf("coming   !!!!!\n");
                        //将正文部分保存到本地磁盘中
                        printf("文件的第 %d部分格式如上,现要将其保存为.txt文件到本地磁盘,文件名请用原始扩展名:\n",m-1);
                        scanf("%s",adrtemp);
                        //文件拷到目标地址
//***                        printf("coming   !!!!!\n");
            filecopy(fpinfile,adrtemp);
                        //调用译码程序
                        printf("o k   !!!!!\n");
            convertmain(adrtemp/*要处理的本地临时文件地址*/);
//***                        printf("coming   !!!!!\n");//问题是convert没有执行?
                }

        }
        fclose(fpinfile);
}


//文件拷贝函数
void filecopy(FILE *fp/*要处理文件指针*/,char adr[20]/*目标地址*/)
{
        //创建一个临时文本文件
        FILE *tempfp;
        char ch[100];
    tempfp=fopen(adr,"w");
        if(tempfp==NULL)
        {
                printf("临时文件未能创建!!!\n");
                return;
        }
        //当遇到一行只有一个回车符或者遇到分界符的时候,停止copy
        while(ch[0]!='\n')
        {
                fgets(ch,100,fp);
                if((ch[0]!='-')&&(ch[0]!='\n'))//回车和无效字符都不能写进要编译的文本
                        fputs(ch,tempfp);//当连着拷进两个回车符时,译码程序不能识别,
                else               //将最后一个回车作为文件结束,这样文件将比实际多出两个字符
                {
                        ch[0]=NULL;
                        break;
                }

        }
        fclose(tempfp);
}
//数组有效字符计数
int strcount(char fstr[100])
{
    int i=0;
        while(fstr!='\0')
        {
                i++;
        }
        return i+1;

}
//Content-Type字符串查找
int checkct(char fin[100],int n)
{
        char ctype[20]="Content-Type";
    int i;
    int j;
        int m;
        int k=0;//返回标志
        for(i=0;i<n;i++)
        {
                j=i;
                m=0;
                //先找Content-Type项
                while(fin[j]==ctype[m])
                {
                        j++;
                        m++;
                        if(ctype[m]=='\0')
                        {
                                printf("%s",fin);
                                k=1;
                                break;
                        }
                }               
        }
        return k;
}
//filename查找
int checkfi(char fin[100],int n)
{
        char fname[20]="filename";
    int i;
    int j;
        int m;
        int k=0;//返回条件变量
        for(i=0;i<n;i++)
        {
                j=i;
                m=0;
                while(fin[j]==fname[m])
                {
                        j++;
                        m++;
                        if(fname[m]=='\0')
                        {
                                printf("%s",fin);
                                k=1;
                                break;
                        }
                }
        }
        return k;
}


//—————————————————————————————————————————
//**********************************************************************************
//—————————————————————————————————————————

void convertmain(char adrin[20]/*要处理的本地临时文件地址*/)
{                  
      FILE *fpinfile;
      char adrout[20];
          int  character;
      fpinfile=fopen(adrin,"r");
       if(fpinfile==0)
           {
                printf("can't open the file,please check your URL.");
                return;
           }
            printf("参照上面的输出,输入原始文件的文件格式\n");
                printf("二进制文件选:1\n");
                printf("ASCII文件选: 0\n");
        scanf("%d",&character);
                FILE *fpoutfile;
            printf("输入原始文件保存地址,名称及文件保存格式:\n");
            scanf("%s",adrout);
                if(character==1)
                        fpoutfile=fopen(adrout,"wb");//创建一个二进制文件
                else
            fpoutfile=fopen(adrout,"w"); //创建一个文本文件            
       if(fpoutfile==0)
           {
                printf("can't create the file,please check your URL.");
                return;
           }
           int innumf,outnumf;                               //base64文件大小
           innumf=counter(fpinfile);
           fclose(fpinfile);           //必须注意在进行一次计数后文件的指针已经指向文件末尾
           fpinfile=fopen(adrin,"r");  //对文件以读格式重新打开很重要
       if(fpinfile==0)
           {
                printf("can't open the file again,please check your URL.");
                return;
           }
           printf("编码后文件长度:%d\n",innumf);
           outnumf=B64Decode( fpoutfile, fpinfile,innumf ) ;//处理后文件大小
           printf("原始文件字节数%d\n",outnumf);
                                       
       fclose(fpinfile);
           fclose(fpoutfile);
}
//文件大小计算函数
int counter(FILE *in_file)
{
        int count=0;       
        int   ch;
        while(1)
        {
                ch=fgetc(in_file);
                if(ch==EOF)
                        break;
                ++count;
        }
     return(count);
       
}

//源文件字符到64进制数转换函数

   /*base64的64个基数分别是:A、B、C……Z、a、b、c……z、0、1、2……9、+、/。
    一般在标准编码文件中一般不会出现无效字符*/

unsigned short Chr2Base( char c )
{

   if ( c >= 'A' && c <= 'Z' )
        return (unsigned short)( c - 'A' );              /*0--25*/
    else if ( c >= 'a' && c <= 'z' )
        return (unsigned short)( c - 'a' + 26 );         /*26--51*/
    else if ( c >= '0' && c <= '9' )
        return (unsigned short)( c - '0' + 52 );         /*52--61*/
    else if ( c == '+' )
       return 62;                                         //62
    else if ( c == '/' )
        return 63;                                         //63
    else
        return 64;  //  无效字符
}

//base64文件到原始文件译码函数
int B64Decode( FILE *fpoutfile, FILE *fpinfile,int n )      //n为要处理文件大小
{                                             
    int             i,j=0;
    unsigned char   t;
        char tt;
        int ch;
        unsigned short c;
        unsigned char   resl;

    for ( i = 0; i < n; i++ )
    {
                ch=fgetc(fpinfile);
        if ((char)ch=='=')//base64在将原始文件编码时是每三个字符一处理输入不够三字府时用“=”补足
            break;        //所以“=”出现的个数不超过2个,并且“=”不参与编码,当然也就不能译码了
                if ((char)ch=='\n')
                ch=fgetc(fpinfile);//遇到回车则再读一次,这是对一行读完后遇到回车符的处理
        do {

                        if (ch!=EOF)
                        {       
                                tt=(char)ch;
//                                printf("%c",tt);
                                c = Chr2Base((char)ch);//调用Chr2Base读字符,并转成0--63的其中之一
//既然Chr2Base()是将字符一个一个处理的,这样我就可以用fgetc()将源文件中的字符读出,将返回值变为字符形式。
                               
                        }       
       
           else
                c = 65;         //  字符串结束
                } while (c==64);        //  跳过无效字符,如回车等
                                        //64进制数并没有参与运算,而是用于判断
//       printf("out");
                if ( c==65)
            break;
       switch ( i % 4 )         /*4个字符为一组处理*/
       {
        case 0 :
            t = c << 2;     //主意:在进行移位操作时,c的原始值是系统保留的
            break;
                case 1:
            resl = (unsigned char)(t | ( c >> 4 ));          //译码后的第一个字符;
                        fputc(resl,fpoutfile);
//                        printf("%d:%d\n", j, resl);
                        j=j+1;
            
                                //能不能在循环的同时就将他写入目标文件?写的时候是直接使用二进制吗?
            t = ( c << 4 );         
            break;
                case 2:
            resl = (unsigned char)(( t | ( c >> 2 ) )&255);          //译码后的第二个字符
            fputc(resl,fpoutfile);
//                        printf("%d:%d\n", j, resl);
                        j=j+1;
                        t = ( c << 6 );
            break;
        case 3 :
            resl = (unsigned char)(( t | c )&255);                   //译码后的第三个字符
            fputc(resl,fpoutfile);
//                        printf("%d:%d\n", j, resl);
                        j=j+1;
                    break;
           }
    }
    return(j);        
}

论坛徽章:
0
发表于 2009-04-14 14:20 |显示全部楼层
太简单了吧, Content-Type会有很多种类型,另外还有RFC很多要求根本没有实现.

论坛徽章:
0
发表于 2009-04-14 14:25 |显示全部楼层
原帖由 nmzqzw 于 2009-4-14 14:20 发表
太简单了吧, Content-Type会有很多种类型,另外还有RFC很多要求根本没有实现.

本科毕业设计,呵呵
什么是RFC,呵呵,这个概念太大了,当初只是这么一点东西,我也翻阅了大量的RFC文档,呵呵。
Content-Type好像都是以字符编码的方式进行发送的,所以才有编码和解码之分,要不就直接发送了

论坛徽章:
0
发表于 2009-04-14 14:35 |显示全部楼层
按附件发出来,会更好吧

共享精神是值得赞扬的

论坛徽章:
0
发表于 2009-04-14 15:26 |显示全部楼层

回复 #3 jerry_lee 的帖子

Received:

Received: X-SENDER-IP:
X-LOGIN-NAME:
X-ATTACHMENT-NUM:1
X-SENDER:
Received
From: To:
Subject: rtftest
Date: Fri, 10 Apr 2009 16:48:24 +0800
Message-ID: <4F9253A7C4694E1088200A51A23C4FCF@PC20090408XIAV>
MIME-Version: 1.0
Content-Type: multipart/mixed;
        boundary="----=_NextPart_000_0006_01C9B9FC.29CA22E0"
X-Mailer: Microsoft Office Outlook 11
Thread-Index: Acm5uRnOAfTezO+2TA+Q+jm6Hd7OcA==
X-MimeOLE: Produced By Microsoft MimeOLE V6.00.2900.5579
X-MS-TNEF-Correlator: 0000000035017CFB0476E04291952CECA37CE606E4052000

This is a multi-part message in MIME format.

------=_NextPart_000_0006_01C9B9FC.29CA22E0
Content-Type: text/plain;
        charset="us-ascii"
Content-Transfer-Encoding: 7bit

rtf test

------=_NextPart_000_0006_01C9B9FC.29CA22E0
Content-Type: application/ms-tnef;
        name="winmail.dat"
Content-Transfer-Encoding: base64
Content-Disposition: attachment;
        filename="winmail.dat"
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP