xml_attached_file.c
author ali@yendor.vm.bytemark.co.uk
Thu Nov 16 08:30:26 2006 +0000 (2006-11-16)
changeset 0 ae7b3fa753dc
permissions -rw-r--r--
First cut. Distintly raw around the edges:
* Assumes it will be running in /home/ali/wk/slashem/web.scripts
* Assumes cache directory will be in topdir
* No build system (simple compiling and linking against libxml2)
* No configure system (eg., tagsoup)
* Output XML untested
* Doesn't set bugzilla maintainer or exporter
* Handling of artifact priorities and resolution is suspect
     1 /*
     2  * This program converts an attached file (which has previously been
     3  * downloaded from sourceforge) into bugzilla-style XML.
     4  */
     5 
     6 #include <stdlib.h>
     7 #include <stdio.h>
     8 #include <string.h>
     9 #ifdef __linux__
    10 #include <getopt.h>
    11 #endif
    12 
    13 #ifdef __linux__
    14 static struct option long_options[] = {
    15     {"type", 1, 0, 't'},
    16     {"id", 1, 0, 'i'},
    17     {"patch", 0, 0, 'p'},
    18     {0, 0, 0, 0}
    19 };
    20 
    21 static char *long_option_str(char opt)
    22 {
    23     int i;
    24     static char buf[100];
    25     for(i=0;long_options[i].name;i++)
    26 	if (long_options[i].val==opt)
    27 	{
    28 	    sprintf(buf,", --%s",long_options[i].name);
    29 	    return buf;
    30 	}
    31     return "";
    32 }
    33 #else
    34 #define long_option_str(opt)    ""
    35 #endif
    36 
    37 usage()
    38 {
    39     fprintf(stderr,"Usage: xml_attached_file [OPTION] file\n");
    40     fprintf(stderr,"\n");
    41     fprintf(stderr,"  -t%s=MIME-type	    MIME type to use\n",
    42       long_option_str('t'));
    43     fprintf(stderr,"  -i%s=ID	            Attachment ID to use\n",
    44       long_option_str('i'));
    45     fprintf(stderr,"  -p%s	            Mark attachment as a patch\n",
    46       long_option_str('p'));
    47     exit(1);
    48 }
    49 
    50 /* Note that we limit line lengths to 76 characters following RFC 2045
    51  * (bugzilla uses MIME::Base64). This isn't strictly compliant with RFC 4648.
    52  */
    53 static void base64_encode(FILE *in,FILE *out)
    54 {
    55     int ng=0;		/* 76 characters == 19 groups */
    56     size_t nb;
    57     unsigned char bytes[3];
    58     const char alphabet[64]=
    59       "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
    60     while ((nb=fread(bytes,1,3,in))==3)
    61     {
    62 	if (ng++>=19)
    63 	{
    64 	    putc('\n',out);
    65 	    ng=1;
    66 	}
    67 	putc(alphabet[bytes[0]>>2],out);
    68 	putc(alphabet[(bytes[0]<<4|bytes[1]>>4)&0x3F],out);
    69 	putc(alphabet[(bytes[1]<<2|bytes[2]>>6)&0x3F],out);
    70 	putc(alphabet[bytes[2]&0x3F],out);
    71     }
    72     if (nb)
    73     {
    74 	if (ng>=19)
    75 	    putc('\n',out);
    76 	putc(alphabet[bytes[0]>>2],out);
    77 	if (nb==2)
    78 	{
    79 	    putc(alphabet[(bytes[0]<<4|bytes[1]>>4)&0x3F],out);
    80 	    putc(alphabet[bytes[1]<<2&0x3F],out);
    81 	}
    82 	else
    83 	{
    84 	    putc(alphabet[bytes[0]<<4&0x3F],out);
    85 	    putc('=',out);
    86 	}
    87 	putc('=',out);
    88     }
    89 }
    90 
    91 int main(int argc,char **argv)
    92 {
    93     int c;
    94     FILE *fp;
    95     unsigned long id=0;
    96     int ispatch=0;
    97     char *type=NULL;
    98     for(;;)
    99     {
   100 #ifdef __linux__
   101 	int option_index=0;
   102 	c=getopt_long(argc,argv,"t:i:p",long_options,&option_index);
   103 #else
   104 	c=getopt(argc,argv,"t:i:p");
   105 #endif
   106 	if (c<0)
   107 	    break;
   108 	switch(c)
   109 	{
   110 	    case 't':
   111 		type=optarg;
   112 		break;
   113 	    case 'i':
   114 		id=strtoul(optarg,NULL,10);
   115 		break;
   116 	    case 'p':
   117 		ispatch=1;
   118 		break;
   119 	    default:
   120 		usage();
   121 	}
   122     }
   123     if (optind<argc)
   124     {
   125 	fp=fopen(argv[optind],"rb");
   126 	if (!fp)
   127 	{
   128 	    perror(argv[optind]);
   129 	    exit(1);
   130 	}
   131     }
   132     else
   133 	fp=stdin;
   134     printf("<attachment ispatch=\"%d\">\n",ispatch);
   135     if (id)
   136 	printf("  <attachid>%lu</attachid>\n",id);
   137     if (type)
   138 	printf("  <type>%s</type>\n",type);
   139     printf("  <data encoding=\"base64\">\n");
   140     base64_encode(fp,stdout);
   141     printf("\n  </data>\n");
   142     printf("</attachment>\n");
   143     exit(0);
   144 }