当前位置 博文首页 > 积水成渊:(原创) linux 下给多人发送邮件源码(SMTP协议)

    积水成渊:(原创) linux 下给多人发送邮件源码(SMTP协议)

    作者:[db:作者] 时间:2021-07-29 12:38

    ?直接贴代码吧~~~~

    1. mail.c

    ///
    //mail.c:
    #include "mail.h"
    #include "base64.h"
    #include <string.h>
    #include <stdlib.h>
    #include <stdio.h>
    #include <arpa/inet.h>
    #include <netinet/in.h>
    #include <netdb.h>
    #include <unistd.h>
    #include <ctype.h>
    #include <time.h>
    
    static char
        *months [] = {
            "Jan", "Feb", "Mar", "Apr", "May", "Jun",
            "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
            };
    static char
        *days [] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
    
    char * encode_mime_time (long date, long time);
    void local_to_gmt (long date, long time, long *gmt_date, long *gmt_time);
    time_t date_to_timer (long date, long time);
    long timer_to_gmdate (time_t time_secs);
    long timer_to_gmtime (time_t time_secs);
    int day_of_week (long date);
    long time_now (void);
    long date_now (void);
    
    
    
    #define GET_MONTH(d)        (int) (((d) % 10000L) / 100)
    #define GET_DAY(d)          (int) ( (d) % 100)
    #define GET_CCYEAR(d)       (int) ( (d) / 10000L)
    #define GET_YEAR(d)         (int) (((d) % 1000000L) / 10000L)
    #define GET_HOUR(t)         (int) ( (t) / 1000000L)
    #define GET_MINUTE(t)       (int) (((t) % 1000000L) / 10000L)
    #define GET_SECOND(t)       (int) (((t) % 10000L) / 100)
    #define MAKE_DATE(c,y,m,d)  (long) (c) * 1000000L +                          \
                                (long) (y) * 10000L +                            \
                                (long) (m) * 100 + (d)
    #define MAKE_TIME(h,m,s,c)  (long) (h) * 1000000L +                          \
                                (long) (m) * 10000L +                            \
                                (long) (s) * 100 + (c)
    
    
    /*  ---------------------------------------------------------------------[<]-
        Function: encode_mime_time
    
        Synopsis: Encode date and time (in long format) in Mime RFC1123 date
        format, e.g. Mon, 12 Jan 1995 12:05:01 GMT.  The supplied date and time
        are in local time.  Returns the date/time string if the date was legal,
        else returns "?".  Returned string is in a static buffer.
        ---------------------------------------------------------------------[>]-*/
    
    char * encode_mime_time (long date, long time)
    {
        int day_week,                       /*  Day of week number (0 is sunday) */
        	month;                          /*  Month number                     */
        static char buffer [50];
    
        local_to_gmt (date, time, &date, &time);
        day_week = day_of_week (date);
        month    = GET_MONTH   (date);
        if (day_week >= 0 && day_week < 7 && month > 0 && month < 13)
          {
            sprintf (buffer, "%s, %02d %s %04d %02d:%02d:%02d GMT",
                             days       [day_week],
                             GET_DAY    (date),
                             months     [month - 1],
                             GET_CCYEAR (date),
                             GET_HOUR   (time),
                             GET_MINUTE (time),
                             GET_SECOND (time)
                     );
            return (buffer);
          }
        else
            return ("?");
    } //end proc encode_mime_time()
    
    
    
    /*  ---------------------------------------------------------------------[<]-
        Function: local_to_gmt
    
        Synopsis: Converts the specified date and time to GMT.  Returns the GMT
        date and time in two arguments.
        ---------------------------------------------------------------------[>]-*/
    
    void local_to_gmt (long date, long time, long *gmt_date, long *gmt_time)
    {
        time_t time_value;
    
        time_value = date_to_timer   (date, time);
        *gmt_date  = timer_to_gmdate (time_value);
        *gmt_time  = timer_to_gmtime (time_value);
    } //end proc local_to_gmt()
    
    
    /*  ---------------------------------------------------------------------[<]-
        Function: date_to_timer
    
        Synopsis: Converts the supplied date and time into a time_t timer value.
        This is the number of non-leap seconds since 00:00:00 GMT Jan 1, 1970.
        Function was rewritten by Bruce Walter <walter@fortean.com>.  If the
        input date and time are invalid, returns 0.
        ---------------------------------------------------------------------[>]-*/
    
    time_t date_to_timer (long date, long time)
    {
        struct tm time_struct;
        time_t timer;
    
        time_struct.tm_sec   = GET_SECOND (time);
        time_struct.tm_min   = GET_MINUTE (time);
        time_struct.tm_hour  = GET_HOUR   (time);
        time_struct.tm_mday  = GET_DAY    (date);
        time_struct.tm_mon   = GET_MONTH  (date) - 1;
        time_struct.tm_year  = GET_CCYEAR (date) - 1900;
        time_struct.tm_isdst = -1;
        timer = mktime (&time_struct);
        if (timer == -1)
            return (0);
        else
            return (timer);
    } //end proc date_to_timer()
    
    /*  ---------------------------------------------------------------------[<]-
       Function: timer_to_date
    
        Synopsis: Converts the supplied timer value into a long date value.
        Dates are stored as long values: CCYYMMDD.  If the supplied value is
        zero, returns zero.  If the supplied value is out of range, returns
        1 January, 1970 (19700101). The timer value is assumed to be UTC (GMT).
        ---------------------------------------------------------------------[>]-*/
    
    long timer_to_date (time_t time_secs)
    {
        struct tm *time_struct;
    
       if (time_secs == 0)
            return (0);
        else
          {
            /*  Convert into a long value CCYYMMDD                               */
            time_struct = localtime (&time_secs);
            if (time_struct)
              {
                time_struct-> tm_year += 1900;
                return (MAKE_DATE (time_struct-> tm_year / 100,
                                   time_struct-> tm_year % 100,
                                   time_struct-> tm_mon + 1,
                                   time_struct-> tm_mday));
              }
            else
                return (19700101);
          }
    } //end proc timer_to_date()
    
    /*  ---------------------------------------------------------------------[<]-
        Function: timer_to_time
    
        Synopsis: Converts the supplied timer value into a long time value.
        Times are stored as long values: HHMMSS00.  Since the timer value does
        not hold centiseconds, these are set to zero.  If the supplied value
        was zero or invalid, returns zero.  The timer value is assumed to be UTC
        (GMT).
        ---------------------------------------------------------------------[>]-*/
    
    long timer_to_time (time_t time_secs)
    {
        struct tm *time_struct;
    
        if (time_secs == 0)
            return (0);
        else
          {
            /*  Convert into a long value HHMMSS00                               */
            time_struct = localtime (&time_secs);
            if (time_struct)
                return (MAKE_TIME (time_struct-> tm_hour,
                                   time_struct-> tm_min,
                                   time_struct-> tm_sec,
                                   0));
            else
                return (0);
          }
    } //end proc timer_to_time()
    
    
    /*  ---------------------------------------------------------------------[<]-
        Function: timer_to_gmdate
    
        Synopsis: Converts the supplied timer value into a long date value in
        Greenwich Mean Time (GMT).  Dates are stored as long values: CCYYMMDD.
        If the supplied value is zero, returns zero.  If the supplied value is
        out of range, returns 1 January, 1970 (19700101).
        ---------------------------------------------------------------------[>]-*/
    
    long timer_to_gmdate (time_t time_secs)
    {
        struct tm *time_struct;
    
        if (time_secs == 0)
            return (0);
        else
          {
            /*  Convert into a long value CCYYMMDD                               */
            time_struct = gmtime (&time_secs);
            if (time_struct == NULL)        /*  If gmtime is not implemented     */
                time_struct = localtime (&time_secs);
    
            if (time_struct)
              {
                time_struct-> tm_year += 1900;
                return (MAKE_DATE (time_struct-> tm_year / 100,
                                   time_struct-> tm_year % 100,
                                   time_struct-> tm_mon + 1,
                                   time_struct-> tm_mday));
              }
            else
                return (19700101);          /*  We had an invalid date           */
          }
    } //end proc timer_to_gmdate()
    
    
    /*  ---------------------------------------------------------------------[<]-
        Function: timer_to_gmtime
    
        Synopsis: Converts the supplied timer value into a long time value in
        Greenwich Mean Time (GMT).  Times are stored as long values: HHMMSS00.
        On most systems the clock does not return centiseconds, so these are
        set to zero.  If the supplied value is zero or invalid, returns zero.
        ---------------------------------------------------------------------[>]-*/
    
    long timer_to_gmtime (time_t time_secs)
    {
        struct tm *time_struct;
    
        if (time_secs == 0)
            return (0);
        else
          {
            /*  Convert into a long value HHMMSS00                               */
            time_struct = gmtime (&time_secs);
            if (time_struct == NULL)        /*  If gmtime is not implemented     */
                time_struct = localtime (&time_secs);
    
            if (time_struct)
                return (MAKE_TIME (time_struct-> tm_hour,
                                   time_struct-> tm_min,
                                   time_struct-> tm_sec,
                                   0));
            else
                return (0);
          }
    } //end proc timer_to_gmtime()
    
    /*  ---------------------------------------------------------------------[<]-
        Function: day_of_week
    
        Synopsis: Returns the day of the week where 0 is Sunday, 1 is Monday,
        ... 6 is Saturday.  Uses Zeller's Congurence algorithm.
        ---------------------------------------------------------------------[>]-*/
    
    int day_of_week (long date)
    {
        int year  = GET_CCYEAR (date),
            month = GET_MONTH  (date),
            day   = GET_DAY    (date);
    
        if (month > 2)
            month -= 2;
        else
        {
            month += 10;
            year--;
        }
        day = ((13 * month - 1) / 5) + day + (year % 100) +
              ((year % 100) / 4) + ((year / 100) / 4) - 2 *
               (year / 100) + 77;
    
        return (day - 7 * (day / 7));
    } //end proc day_of_week()
    
    /*  ---------------------------------------------------------------------[<]-
        Function: time_now
    
        Synopsis: Returns the current time as a long value (HHMMSSCC).  If the
        system clock does not return centiseconds, these are set to zero.
        ---------------------------------------------------------------------[>]-*/
    
    long time_now (void)
    {
        /*  The BSD gettimeofday function returns seconds and microseconds       */
        struct timeval
            time_struct;
    
        gettimeofday (&time_struct, 0);
        return (timer_to_time (time_struct.tv_sec)
                             + time_struct.tv_usec / 10000);
    } //end proc time_now()
    
    /*  ---------------------------------------------------------------------[<]-
        Function: date_now
    
        Synopsis: Returns the current date as a long value (CCYYMMDD).  Since
        most system clocks do not return a century, this function assumes that
        all years 80 and above are in the 20th century, and all years 00 to 79
        are in the 21st century.  For best results, consume before 1 Jan 2080.
        ---------------------------------------------------------------------[>]-*/
    
    long date_now (void)
    {
        return (timer_to_date (time (NULL)));
    } //end proc date_now()
    
    
    
    
    
    /* 判断str开始的字符串是不是start*/
    static int start_str(char *str,const char *start)
    {
        if(strstr(str,start)==str)
            return 1;
        else
            return 0;
    }
    
    /*将命令command发送到SMTP服务器,如果收到响应号为code,则返回true */
    static int do_act(const char *code, mail_data_s *mail)
    {
        if(write(mail->sock,mail->lastact,strlen(mail->lastact))<0)
        {
            perror("write");
            return 0;
        }
        //printf("send : %s\n", mail->lastact);
        memset(mail->lastmessage, 0, sizeof(mail->lastmessage));
        if(read(mail->sock,mail->lastmessage ,255)<0)
        {
            perror("read");
            return 0;
        }
        //printf("recv : %s\n", mail->lastmessage);
        if(start_str(mail->lastmessage,code))
            return 1;
        else
            return 0;
    }
    /* 发送email */
    static int send_mail(mail_data_s *mail, account_s *user)
     {
    	int tocnt = 0;
        char head[255];
        char to[255];
        char *tolist[32];
        char *ptr = NULL;
        struct sockaddr_in sa;
        struct hostent *he;
    
        sa.sin_family = AF_INET;
        sa.sin_port = htons(user->port);
      
        if((he=gethostbyname(user->smtp_server))!=NULL)
            bcopy(he->h_addr,&sa.sin_addr,he->h_length); 
        else
        {
            perror("gethostbyname");
            return -1;
        }     
       
        //strcpy(mail->lastact,"connect");
        mail->sock=socket(AF_INET,SOCK_STREAM,0);
     
        if ( mail->sock )
        {
            if(connect(mail->sock,(struct sockaddr*)&sa,sizeof(struct sockaddr))<0)
            {
                perror("conncect");
                return -1;
            }
    
            read(mail->sock,mail->lastmessage,512);
            if ( !start_str(mail->lastmessage,"220"))
            {
                return -1;
            }
            else
            {
            	/* Now, we must send chat command to smtp server. */
                strcpy(mail->lastact,"HELO ");
                strcat(mail->lastact,mail->welcome);
                strcat(mail->lastact,"\r\n");
                fflush(stdout);
                if(!do_act("250", mail))
                {
                    printf("HELO\n");
                    close(mail->sock);
                    return -1;
                } 
    
                strcpy(mail->lastact,"AUTH LOGIN\r\n");
                if(!do_act("334", mail))
                {
                    printf("AUTH LOGIN\n");
                    close(mail->sock);
                    return -1;
                } 
    
                char *code64=NULL;
                code64=base64_encode(user->username,strlen(user->username));
                strcpy(mail->lastact,code64);
                strcat(mail->lastact,"\r\n");
                if(!do_act("334", mail))
                {
                    printf("user name\n");
                    close(mail->sock);
                    return -1;
                } 
                
                //code64=NULL;
                //code64=base64_encode(user->passwd,strlen(user->passwd));
               // strcpy(mail->lastact,code64);
                strcpy(mail->lastact, user->passwd);
                strcat(mail->lastact,"\r\n");
                if(!do_act("235", mail))
                {
                    printf("passwd\n");
                    close(mail->sock);
                    return -1;
                } 
                            
                strcpy(mail->lastact,"MAIL FROM: ");
                strcat(mail->lastact,mail->from);
                strcat(mail->lastact,"\r\n");
                
                if(!do_act("250", mail))
                {
                    printf("MAIL FROM");
                    close(mail->sock);
                    return -1;
                }
    /*
                strcpy(mail->lastact,"RCPT TO: ");
                strcat(mail->lastact,mail->to);
                strcat(mail->lastact,"\r\n");
                if(!do_act("250", mail))
                {
                    close(mail->sock);
                    return -1;
                }
     */
                /* split mail to address */
                strcpy(to, mail->to);
                ptr = strtok(to, " ");
                tolist[tocnt++] = ptr;
                while((ptr = strtok(NULL, " ")))
                {
                	tolist[tocnt++] = ptr;
                }
                tolist[tocnt] = NULL;
                tocnt = 0;
    
                /* Send peer mail address to smtp server */
                while(tolist[tocnt])
                {
                    strcpy(mail->lastact,"RCPT TO: ");
                    strcat(mail->lastact, tolist[tocnt++]);
                    strcat(mail->lastact,"\r\n");
                    printf("%s \n", mail->lastact);
                    if(!do_act("250", mail))
                    {
                        close(mail->sock);
                        return -1;
                    }
                }
    
                /* Send mail data to smtp server */
                strcpy(mail->lastact,"DATA\r\n");
                if(!do_act("354", mail))
                {
                    close(mail->sock);
                    return -1;
                }
    
                /* Send mail subject to smtp server */
                strcpy(head,"Subject: ");
                strcat(head,mail->subject);
                strcat(head,"\r\n");
                if(strlen(mail->subject)>0)
                {
                    write(mail->sock,head,strlen(head));
                }
    
                /* Send mail sender address to smtp server */
                strcpy(head,"From: ");
                strcat(head,mail->from);
                strcat(head,"\r\n");            
                if(strlen(mail->from)>0)
                {
                    write(mail->sock,head,strlen(head));
                }
    
                /*
                strcpy(head,"To: ");
                //strncat(head,mail->to+1, strlen(mail->to)-2);
                strcat(head,mail->to);
                strcat(head,"\r\n");
                if(strlen(head)>0)
                {
                    write(mail->sock,head,strlen(head));
                } 
    			*/
    
                /* Send mail peer address infomation to smtp server */
                tocnt = 0;
                while(tolist[tocnt])
                {
                    strcpy(head,"To: ");
                    strncat(head, tolist[tocnt] + 1, strlen(tolist[tocnt]) - 2);
                    strcat(head, " ");
                    strcat(head, tolist[tocnt++]);
                    strcat(head,"\r\n");
                    printf("%s \n", head);
                    if(strlen(head)>0)
                    {
                        write(mail->sock,head,strlen(head));
                    }
                }
    
                strcpy (head, "\r\n\r\n");
                if(strlen(head)>0)
                {
                	write(mail->sock, head, strlen(head));
                }
    
                //code64 = NULL;
                //strcpy(head,message);
                //strcat(head,"\r\n");
                //code64=base64_encode(head,strlen(head));
                //strcpy(message,code64);
                /* Send mail message to smtp server */
                strcpy(head, mail->message);
                strcat(head, "\r\n");
                write(mail->sock, head, strlen(head));
    
                strcpy(head, "Date: ");
                strcat(head, encode_mime_time (date_now (), time_now ()));
                strcat(head, "\r\n");
                write(mail->sock, head, strlen(head));
    
                strcpy(head, "\r\n.\r\n");
                write(mail->sock, head, strlen(head));
    
                /* Send quit command to smtp server, then chatting end. */
                strcpy(mail->lastact,"QUIT\r\n");
                if(!do_act("250", mail))
                {
                    close(mail->sock);
                    return -1;
                }
            }
            return 0;
        }
        else
        {
            printf("Connect failed!");
            return -1;
        }
    }
    
    /* Create a mail struct */
    mail_s *new_mail( char *to, char *from, char *welcome, char *subject, char *message)
    {
    	mail_s *mail = NULL;
        if((mail = (mail_s *)calloc(1, sizeof(mail_s))) == NULL)
        	return NULL;
        if(strlen(to)<=0)
        {
        	printf("Mail to cannt be NULL");
        	goto NEW_FAIL;
        }
        else
        {
        	if((mail->data.to = (char *)calloc(1, sizeof(char)*(strlen(to) + 1))))
        		strcpy(mail->data.to, to);
        	else
        		goto NEW_FAIL;
        }
    
        if(strlen(from)<=0)
        {
        	printf("Mail from cannt be NULL");
        	goto PARAM_FAIL;
        }
        else
            strcpy(mail->data.from,from);
    
        if(strlen(subject)<=0)
        {
            strcpy(mail->data.subject,"Test");
        }
        else
            strcpy(mail->data.subject,subject);
    
        if(strlen(welcome)<=0)
        {
            strcpy(mail->data.welcome,"localhost");
        }
        else
            strcpy(mail->data.welcome,welcome);
    
        strcpy(mail->data.lastmessage,"");
        strcpy(mail->data.lastact,"");
    
        mail->data.messagelen = strlen(message);
        if((mail->data.message =  (char *)calloc(1, sizeof(char)*mail->data.messagelen)) == NULL)
        	goto PARAM_FAIL;
        strcpy(mail->data.message, message);
    
        mail->send = &send_mail;
        return mail;
    PARAM_FAIL:
    	free(mail->data.to);
    NEW_FAIL:
    	free(mail);
    	return NULL;
    }
    
    /* Free mail struct */
    void delete_mail( mail_s *mail )
    {
    	free(mail->data.message);
    	free(mail->data.to);
    	free(mail);
    	mail = NULL;
    }
    
    /* Create sender user account struct */
    account_s *new_account(char *username, char *passwd, char *smtp_server, int port)
    {
    	char *code64 = NULL;
    	account_s *user = NULL;
    	if((user = (account_s *)calloc(1, sizeof(account_s))) == NULL)
    		return NULL;
    	memcpy(user->username, username, strlen(username));
    	code64 = base64_encode(passwd, strlen(passwd));
    	strcpy(user->passwd, code64);
    	//memcpy(user->passwd, passwd, strlen(passwd));
    	memcpy(user->smtp_server, smtp_server, strlen(smtp_server));
    	user->port = port;
    	return user;
    }
    
    /* Free account struct */
    void delete_account( account_s *user )
    {
    	free(user);
    	user = NULL;
    }
    
    
    /* Test main */
    int main()
    {
        mail_s *mail = NULL;
        account_s *user = NULL;
        user = new_account("xxx@163.com", "passwd", "smtp.163.com", 25);
        if(!user)
        {
        	printf("Alloc space for account fail.\n");
    	return 0;
        }
        mail = new_mail("<xxx@qq.com> <xxx@163.com>",
        		"<xxx@163.com>", "xxx",  "test", "Hello, this is a test letter!");
        if(!mail)
        {
        	printf("Alloc space for mail fail.\n");
    	goto FREE_USER;
        }
        if(mail->send(&mail->data, user) == 0)
        {
            printf("发送成功!\n");
        }
        else
        {
            printf("发送失败!\n");
        }
        delete_mail(mail);
    FREE_USER:
        delete_account(user);
        return 0;
    }
    


    2. mail.h

    ///
    //mail.h:
    
    typedef struct {
    	char username[32]; //username
    	char passwd[32]; // password
    	char smtp_server[64]; //smtp服务器地址
    	int  port; //smtp端口号,25
    }account_s;
    
    typedef struct user_list{
    	account_s user;
    	struct user_list *next;
    }user_list;
    
    typedef struct {
    	char lastmessage[255]; //记录最后返回的响应信息
    	char lastact[255]; //最后的动作,字符串形式
    	char welcome[255]; //用在HELO后面,欢迎用户
    	char from[64]; //the mail from where
    	char *to; //mail send to where
    	char subject[64]; // mail subject
    	char *message; // send message
    	int  messagelen; //message length
    	int  sock; //socket句柄
    }mail_data_s;
    
    typedef struct {
    	mail_data_s data;
    	int  (*send)(mail_data_s *, account_s *);
    } mail_s;
    
    mail_s *new_mail(char *, char *, char *, char *, char *);
    void delete_mail( mail_s *mail );
    account_s *new_account(char *, char *, char *, int);
    void delete_account( account_s *user );
    

    3. base64.h

    ///
    //base64.h
    //base64编码与解码
    
    #include <stdlib.h>
    #include <string.h>
    
    static char basis_64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; 
     
    #define CHAR64(c)  (((c) < 0 || (c) > 127) ? -1 : index_64[(c)]) 
         
    static signed char index_64[128] = {     
            -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,     
            -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,     
            -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,62, -1,-1,-1,63,     
            52,53,54,55, 56,57,58,59, 60,61,-1,-1, -1,-1,-1,-1,     
            -1, 0, 1, 2,  3, 4, 5, 6,  7, 8, 9,10, 11,12,13,14,     
            15,16,17,18, 19,20,21,22, 23,24,25,-1, -1,-1,-1,-1,     
            -1,26,27,28, 29,30,31,32, 33,34,35,36, 37,38,39,40,     
            41,42,43,44, 45,46,47,48, 49,50,51,-1, -1,-1,-1,-1     
    } ; 
         
    char *base64_encode(const char *value, int vlen) {
        unsigned char oval = 0 ;      
            char *result = (char *)malloc((vlen * 4) / 3 + 5) ;
            char *out = result;     
        while (vlen >= 3) {     
                *out++ = basis_64[value[0] >> 2];     
                *out++ = basis_64[((value[0] << 4) & 0x30) | (value[1] >> 4)];     
                *out++ = basis_64[((value[1] << 2) & 0x3C) | (value[2] >> 6)];     
                *out++ = basis_64[value[2] & 0x3F];     
                value += 3;     
                   vlen -= 3;     
            } 
        if (vlen > 0) {     
                *out++ = basis_64[value[0] >> 2];     
                oval = (value[0] << 4) & 0x30 ;     
                if (vlen > 1) oval |= value[1] >> 4;     
                *out++ = basis_64[oval];     
                *out++ = (vlen < 2) ? '=' : basis_64[(value[1] << 2) & 0x3C];     
                *out++ = '=';     
        }     
        *out = '\0';         
        return result;
    }     
     
    unsigned char *base64_decode(const char *value, int *rlen)     
    {         
        int c1, c2, c3, c4;                 
            int vlen = strlen(value);     
        unsigned char *result =(unsigned char *)malloc((vlen * 3) / 4 + 1);     
        unsigned char *out = result;     
         
        *rlen = 0; 
         
        while (1) {     
            if (value[0]==0) { 
                *out = '\0' ;  
                return result;     
            } 
                c1 = value[0];     
                    if (CHAR64(c1) == -1) goto base64_decode_error; 
                     c2 = value[1];     
                     if (CHAR64(c2) == -1) goto base64_decode_error; 
                     c3 = value[2];     
                     if ((c3 != '=') && (CHAR64(c3) == -1)) goto base64_decode_error; 
                     c4 = value[3];     
                     if ((c4 != '=') && (CHAR64(c4) == -1)) goto base64_decode_error;     
                         value += 4;     
                     *out++ = (CHAR64(c1) << 2) | (CHAR64(c2) >> 4);     
                     *rlen += 1;     
                     if (c3 != '=') {     
                         *out++ = ((CHAR64(c2) << 4) & 0xf0) | (CHAR64(c3) >> 2);     
                        *rlen += 1;     
                        if (c4 != '=') {     
                            *out++ = ((CHAR64(c3) << 6) & 0xc0) | CHAR64(c4);     
                                *rlen += 1;     
                        } 
                     }     
        }     
        base64_decode_error:     
                *result = 0;     
                *rlen = 0;     
                return result;     
    }
    



    cs