* For mailing lists, Alpine adds a description of the type of link
[alpine.git] / pith / maillist.c
blob07912cbaae406a1cc510642fe21083de8caeadb7
1 /*
2 * ========================================================================
3 * Copyright 2013-2022 Eduardo Chappa
4 * Copyright 2006-2007 University of Washington
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * ========================================================================
16 * * * * * * * * * RFC 2369 support routines * * * * * * * *
20 #include "../pith/headers.h"
21 #include "../pith/maillist.h"
22 #include "../pith/state.h"
23 #include "../pith/url.h"
27 * Internal prototypes
29 int rfc2369_parse(char *, RFC2369_S *);
32 * * NOTE * These have to remain in sync with the MLCMD_* macros
33 * in maillist.h. Sorry.
35 static RFC2369FIELD_S rfc2369_fields[] = {
36 {"List-Help",
37 "get information about the list and instructions on how to join",
38 "seek help"},
39 {"List-Unsubscribe",
40 "remove yourself from the list (Unsubscribe)",
41 "UNsubscribe"},
42 {"List-Subscribe",
43 "add yourself to the list (Subscribe)",
44 "Subscribe"},
45 {"List-Post",
46 "send a message to the entire list (Post)",
47 "post a message"},
48 {"List-Owner",
49 "send a message to the list owner",
50 "contact the list owner"},
51 {"List-Archive",
52 "view archive of messages sent to the list",
53 "view the archive"}
57 char **
58 rfc2369_hdrs(char **hdrs)
60 int i;
62 for(i = 0; i < MLCMD_COUNT; i++)
63 hdrs[i] = rfc2369_fields[i].name;
65 hdrs[i] = NULL;
66 return(hdrs);
70 int
71 rfc2369_parse_fields(char *h, RFC2369_S *data)
73 char *ep, *nhp, *tp;
74 int i, rv = FALSE;
76 for(i = 0; i < MLCMD_COUNT; i++)
77 data[i].field = rfc2369_fields[i];
79 for(nhp = h; h; h = nhp){
80 /* coerce h to start of field */
81 for(ep = h;;)
82 if((tp = strpbrk(ep, "\015\012")) != NULL){
83 if(strindex(" \t", *((ep = tp) + 2))){
84 *ep++ = ' '; /* flatten continuation */
85 *ep++ = ' ';
86 for(; *ep; ep++) /* advance past whitespace */
87 if(*ep == '\t')
88 *ep = ' ';
89 else if(*ep != ' ')
90 break;
92 else{
93 *ep = '\0'; /* tie off header data */
94 nhp = ep + 2; /* start of next header */
95 break;
98 else{
99 while(*ep) /* find the end of this line */
100 ep++;
102 nhp = NULL; /* no more header fields */
103 break;
106 /* if length is within reason, see if we're interested */
107 if(ep - h < MLCMD_REASON && rfc2369_parse(h, data))
108 rv = TRUE;
111 return(rv);
116 rfc2369_parse(char *h, RFC2369_S *data)
118 int l, ifield, idata = 0;
119 char *p, *p1, *url, *comment;
121 /* look for interesting name's */
122 for(ifield = 0; ifield < MLCMD_COUNT; ifield++)
123 if(!struncmp(h, rfc2369_fields[ifield].name,
124 l = strlen(rfc2369_fields[ifield].name))
125 && *(h += l) == ':'){
126 /* unwrap any transport encodings */
127 if((p = (char *) rfc1522_decode_to_utf8((unsigned char *) tmp_20k_buf,
128 SIZEOF_20KBUF, ++h)) == tmp_20k_buf)
129 strcpy(h, p); /* assumption #383: decoding shrinks */
131 url = comment = NULL;
132 while(*h){
133 while(*h == ' ')
134 h++;
136 switch(*h){
137 case '<' : /* URL */
138 if((p = strindex(h, '>')) != NULL){
139 url = ++h; /* remember where it starts */
140 *p = '\0'; /* tie it off */
141 h = p + 1; /* advance h */
142 for(p = p1 = url; (*p1 = *p) != '\0'; p++)
143 if(*p1 != ' ')
144 p1++; /* remove whitespace ala RFC */
146 else
147 *h = '\0'; /* tie off junk */
149 break;
151 case '(' : /* Comment */
152 comment = rfc822_skip_comment(&h, LONGT);
153 break;
155 case 'N' : /* special case? */
156 case 'n' :
157 if(ifield == MLCMD_POST
158 && (*(h+1) == 'O' || *(h+1) == 'o')
159 && (!*(h+2) || *(h+2) == ' ')){
160 ; /* yup! */
162 url = h;
163 *(h + 2) = '\0';
164 h += 3;
165 break;
168 default :
169 removing_trailing_white_space(h);
170 if(!url
171 && (url = rfc1738_scan(h, &l))
172 && url == h && l == strlen(h)){
173 removing_trailing_white_space(h);
174 data[ifield].data[idata].value = url;
176 else
177 data[ifield].data[idata].error = h;
179 return(1); /* return junk */
182 while(*h == ' ')
183 h++;
185 switch(*h){
186 case ',' :
187 h++;
189 case '\0':
190 if(url || (comment && *comment)){
191 data[ifield].data[idata].value = url;
192 data[ifield].data[idata].comment = comment;
193 url = comment = NULL;
196 if(++idata == MLCMD_MAXDATA)
197 *h = '\0';
199 default :
200 break;
205 return(idata);