dest.c 4.7 KB

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