dest.c (4804B)
1 #include "common.h" 2 #include "send.h" 3 4 static String* s_parseq(String*, String*); 5 6 /* exports */ 7 dest *dlist; 8 9 extern dest* 10 d_new(String *addr) 11 { 12 dest *dp; 13 14 dp = (dest *)mallocz(sizeof(dest), 1); 15 if (dp == 0) { 16 perror("d_new"); 17 exit(1); 18 } 19 dp->same = dp; 20 dp->nsame = 1; 21 dp->nchar = 0; 22 dp->next = dp; 23 dp->addr = escapespecial(addr); 24 dp->parent = 0; 25 dp->repl1 = dp->repl2 = 0; 26 dp->status = d_undefined; 27 return dp; 28 } 29 30 extern void 31 d_free(dest *dp) 32 { 33 if (dp != 0) { 34 s_free(dp->addr); 35 s_free(dp->repl1); 36 s_free(dp->repl2); 37 free((char *)dp); 38 } 39 } 40 41 /* The following routines manipulate an ordered list of items. Insertions 42 * are always to the end of the list. Deletions are from the beginning. 43 * 44 * The list are circular witht the `head' of the list being the last item 45 * added. 46 */ 47 48 /* Get first element from a circular list linked via 'next'. */ 49 extern dest * 50 d_rm(dest **listp) 51 { 52 dest *dp; 53 54 if (*listp == 0) 55 return 0; 56 dp = (*listp)->next; 57 if (dp == *listp) 58 *listp = 0; 59 else 60 (*listp)->next = dp->next; 61 dp->next = dp; 62 return dp; 63 } 64 65 /* Insert a new entry at the end of the list linked via 'next'. */ 66 extern void 67 d_insert(dest **listp, dest *new) 68 { 69 dest *head; 70 71 if (*listp == 0) { 72 *listp = new; 73 return; 74 } 75 if (new == 0) 76 return; 77 head = new->next; 78 new->next = (*listp)->next; 79 (*listp)->next = head; 80 *listp = new; 81 return; 82 } 83 84 /* Get first element from a circular list linked via 'same'. */ 85 extern dest * 86 d_rm_same(dest **listp) 87 { 88 dest *dp; 89 90 if (*listp == 0) 91 return 0; 92 dp = (*listp)->same; 93 if (dp == *listp) 94 *listp = 0; 95 else 96 (*listp)->same = dp->same; 97 dp->same = dp; 98 return dp; 99 } 100 101 /* Look for a duplicate on the same list */ 102 int 103 d_same_dup(dest *dp, dest *new) 104 { 105 dest *first = dp; 106 107 if(new->repl2 == 0) 108 return 1; 109 do { 110 if(strcmp(s_to_c(dp->repl2), s_to_c(new->repl2))==0) 111 return 1; 112 dp = dp->same; 113 } while(dp != first); 114 return 0; 115 } 116 117 /* Insert an entry into the corresponding list linked by 'same'. Note that 118 * the basic structure is a list of lists. 119 */ 120 extern void 121 d_same_insert(dest **listp, dest *new) 122 { 123 dest *dp; 124 int len; 125 126 if(new->status == d_pipe || new->status == d_cat) { 127 len = new->repl2 ? strlen(s_to_c(new->repl2)) : 0; 128 if(*listp != 0){ 129 dp = (*listp)->next; 130 do { 131 if(dp->status == new->status 132 && strcmp(s_to_c(dp->repl1), s_to_c(new->repl1))==0){ 133 /* remove duplicates */ 134 if(d_same_dup(dp, new)) 135 return; 136 /* add to chain if chain small enough */ 137 if(dp->nsame < MAXSAME 138 && dp->nchar + len < MAXSAMECHAR){ 139 new->same = dp->same; 140 dp->same = new; 141 dp->nchar += len + 1; 142 dp->nsame++; 143 return; 144 } 145 } 146 dp = dp->next; 147 } while (dp != (*listp)->next); 148 } 149 new->nchar = strlen(s_to_c(new->repl1)) + len + 1; 150 } 151 new->next = new; 152 d_insert(listp, new); 153 } 154 155 /* 156 * Form a To: if multiple destinations. 157 * The local! and !local! checks are artificial intelligence, 158 * there should be a better way. 159 */ 160 extern String* 161 d_to(dest *list) 162 { 163 dest *np, *sp; 164 String *s; 165 int i, n; 166 char *cp; 167 168 s = s_new(); 169 s_append(s, "To: "); 170 np = list; 171 i = n = 0; 172 do { 173 np = np->next; 174 sp = np; 175 do { 176 sp = sp->same; 177 cp = s_to_c(sp->addr); 178 179 /* hack to get local! out of the names */ 180 if(strncmp(cp, "local!", 6) == 0) 181 cp += 6; 182 183 if(n > 20){ /* 20 to appease mailers complaining about long lines */ 184 s_append(s, "\n\t"); 185 n = 0; 186 } 187 if(i != 0){ 188 s_append(s, ", "); 189 n += 2; 190 } 191 s_append(s, cp); 192 n += strlen(cp); 193 i++; 194 } while(sp != np); 195 } while(np != list); 196 197 return unescapespecial(s); 198 } 199 200 /* expand a String of destinations into a linked list of destiniations */ 201 extern dest * 202 s_to_dest(String *sp, dest *parent) 203 { 204 String *addr; 205 dest *list=0; 206 dest *new; 207 208 if (sp == 0) 209 return 0; 210 addr = s_new(); 211 while (s_parseq(sp, addr)!=0) { 212 addr = escapespecial(addr); 213 if(shellchars(s_to_c(addr))){ 214 while(new = d_rm(&list)) 215 d_free(new); 216 break; 217 } 218 new = d_new(addr); 219 new->parent = parent; 220 new->authorized = parent->authorized; 221 d_insert(&list, new); 222 addr = s_new(); 223 } 224 s_free(addr); 225 return list; 226 } 227 228 #undef isspace 229 #define isspace(c) ((c)==' ' || (c)=='\t' || (c)=='\n') 230 231 /* Get the next field from a String. The field is delimited by white space. 232 * Anything delimited by double quotes is included in the string. 233 */ 234 static String* 235 s_parseq(String *from, String *to) 236 { 237 int c; 238 239 if (*from->ptr == '\0') 240 return 0; 241 if (to == 0) 242 to = s_new(); 243 for (c = *from->ptr;!isspace(c) && c != 0; c = *(++from->ptr)){ 244 s_putc(to, c); 245 if(c == '"'){ 246 for (c = *(++from->ptr); c && c != '"'; c = *(++from->ptr)) 247 s_putc(to, *from->ptr); 248 s_putc(to, '"'); 249 if(c == 0) 250 break; 251 } 252 } 253 s_terminate(to); 254 255 /* crunch trailing white */ 256 while(isspace(*from->ptr)) 257 from->ptr++; 258 259 return to; 260 }