1 /* $Id: sm.c 6682 2004-03-06 18:31:15Z rra $
3 ** Provide a command line interface to the storage manager
9 #include "inn/innconf.h"
10 #include "inn/messages.h"
14 static const char usage[] = "\
15 Usage: sm [-dHiqrRS] [token ...]\n\
17 Command-line interface to the INN storage manager. The default action is\n\
18 to display the complete article associated with each token given. If no\n\
19 tokens are specified on the command line, they're read from stdin, one per\n\
22 -d, -r Delete the articles associated with the given tokens\n\
23 -H Display the headers of articles only\n\
24 -i Translate tokens into newsgroup names and article numbers\n\
25 -q Suppress all error messages except usage\n\
26 -R Display the raw article rather than undoing wire format\n\
27 -S Output articles in rnews batch file format\n";
29 /* The options that can be set on the command line, used to determine what to
30 do with each token. */
32 bool artinfo; /* Show newsgroup and article number. */
33 bool delete; /* Delete articles instead of showing them. */
34 bool header; /* Display article headers only. */
35 bool raw; /* Show the raw wire-format articles. */
36 bool rnews; /* Output articles as rnews batch files. */
41 ** Process a single token, performing the operations specified in the given
42 ** options struct. Calls warn and die to display error messages; -q is
43 ** implemented by removing all the warn and die error handlers.
46 process_token(const char *id, const struct options *options)
49 struct artngnum artinfo;
55 warn("%s is not a storage token", id);
58 token = TextToToken(id);
60 if (options->artinfo) {
61 if (!SMprobe(SMARTNGNUM, &token, &artinfo)) {
62 warn("could not get article information for %s", id);
65 printf("%s: %lu\n", artinfo.groupname, artinfo.artnum);
66 free(artinfo.groupname);
68 } else if (options->delete) {
69 if (!SMcancel(token)) {
70 warn("could not remove %s: %s", id, SMerrorstr);
74 article = SMretrieve(token, options->header ? RETR_HEAD : RETR_ALL);
75 if (article == NULL) {
76 warn("could not retrieve %s", id);
80 if (fwrite(article->data, article->len, 1, stdout) != 1)
83 text = FromWireFmt(article->data, article->len, &length);
85 printf("#! rnews %lu\n", (unsigned long) length);
86 if (fwrite(text, length, 1, stdout) != 1)
90 SMfreearticle(article);
97 main(int argc, char *argv[])
101 struct options options = { false, false, false, false, false };
103 message_program_name = "sm";
105 if (!innconf_read(NULL))
108 while ((option = getopt(argc, argv, "iqrdRSH")) != EOF) {
112 options.delete = true;
115 options.header = true;
118 options.artinfo = true;
121 message_handlers_warn(0);
122 message_handlers_die(0);
128 options.rnews = true;
131 fprintf(stderr, usage);
136 /* Check options for consistency. */
137 if (options.artinfo && options.delete)
138 die("-i cannot be used with -r, -d");
139 if (options.artinfo && (options.header || options.raw || options.rnews))
140 die("-i cannot be used with -H, -R, or -S");
141 if (options.delete && (options.header || options.rnews))
142 die("-r or -d cannot be used with -H or -S");
143 if (options.raw && options.rnews)
144 die("-R cannot be used with -S");
145 if (options.header && options.rnews)
146 die("-H cannot be used with -S");
148 /* Initialize the storage manager. If we're doing article deletions, we
149 need to open it read/write. */
150 if (options.delete) {
153 if (!SMsetup(SM_RDWR, &value))
154 die("cannot set up storage manager");
157 die("cannot initialize storage manager: %s", SMerrorstr);
159 /* Process tokens. If no arguments were given on the command line,
160 process tokens from stdin. Otherwise, walk through the remaining
161 command line arguments. */
163 if (optind == argc) {
167 qp = QIOfdopen(fileno(stdin));
168 for (line = QIOread(qp); line != NULL; line = QIOread(qp)) {
169 status = process_token(line, &options);
170 okay = okay && status;
174 die("input line too long");
175 sysdie("error reading stdin");
181 for (i = optind; i < argc; i++) {
182 status = process_token(argv[i], &options);
183 okay = okay && status;