]>
Commit | Line | Data |
---|---|---|
c441a31a | 1 | /* $Id$ |
7ac48069 | 2 | * |
3 | * This is the file printer.c for the Moira Client, which allows users | |
59ec8dae | 4 | * to quickly and easily maintain most parts of the Moira database. |
cc5b487a | 5 | * It Contains: Functions for handling the printers. |
5eaef520 | 6 | * |
cc5b487a | 7 | * Created: 8/16/88 |
8 | * By: Theodore Y. Ts'o | |
9 | * | |
7ac48069 | 10 | * Copyright (C) 1988-1998 by the Massachusetts Institute of Technology. |
11 | * For copying and distribution information, please see the file | |
12 | * <mit-copyright.h>. | |
cc5b487a | 13 | */ |
14 | ||
7ac48069 | 15 | #include <mit-copyright.h> |
8defc06b | 16 | #include <moira.h> |
17 | #include <moira_site.h> | |
cc5b487a | 18 | #include "defs.h" |
19 | #include "f_defs.h" | |
20 | #include "globals.h" | |
cc5b487a | 21 | |
7ac48069 | 22 | #include <stdio.h> |
23 | #include <stdlib.h> | |
24 | #include <string.h> | |
25 | ||
26 | RCSID("$Header$"); | |
27 | ||
28064364 | 28 | void RealDeletePrn(char **info, Bool one_item); |
29 | void ChangePrn(char **info, Bool one_item); | |
30 | extern int GetAliasValue(int argc, char **argv, void *retval); | |
31 | int StoreHWAddr(int argc, char **argv, void *retval); | |
7ac48069 | 32 | |
28064364 | 33 | #define BY_NAME 0 |
34 | #define BY_ETHERNET 1 | |
35 | #define BY_HOSTNAME 2 | |
36 | #define BY_RM 3 | |
37 | #define BY_LOCATION 4 | |
38 | #define BY_CONTACT 5 | |
39 | ||
40 | #define DEFAULT_LOGHOST "WSLOGGER.MIT.EDU" | |
41 | ||
42 | int StoreHWAddr(int argc, char **argv, void *retval) | |
43 | { | |
44 | char **p = retval; | |
45 | *p = strdup(argv[0]); | |
46 | return MR_CONT; | |
47 | } | |
cc5b487a | 48 | |
49 | /* Function Name: SetDefaults | |
50 | * Description: sets the default values for filesystem additions. | |
5eaef520 | 51 | * Arguments: info - an array of char pointers to recieve defaults. |
cc5b487a | 52 | * Returns: char ** (this array, now filled). |
53 | */ | |
54 | ||
5eaef520 | 55 | static char **SetDefaults(char **info, char *name) |
cc5b487a | 56 | { |
28064364 | 57 | info[PRN_NAME] = strdup(name); |
58 | info[PRN_TYPE] = strdup("PRIVATE"); | |
59 | info[PRN_HWTYPE] = strdup("HP"); | |
60 | info[PRN_DUPLEXNAME] = strdup(""); | |
61 | info[PRN_HOSTNAME] = strdup(name); | |
62 | info[PRN_LOGHOST] = strdup(DEFAULT_LOGHOST); | |
63 | info[PRN_RM] = strdup("[ANY]"); | |
64 | info[PRN_RP] = strdup(name); | |
65 | info[PRN_RQ] = strdup("[NONE]"); | |
66 | info[PRN_KA] = strdup("1"); | |
67 | info[PRN_PC] = strdup("10"); | |
68 | info[PRN_AC] = strdup("[none]"); | |
69 | info[PRN_LPC_ACL] = strdup("[none]"); | |
70 | info[PRN_LOCATION] = strdup(""); | |
71 | info[PRN_CONTACT] = strdup(""); | |
72 | info[PRN_MODTIME] = info[PRN_MODBY] = info[PRN_MODWITH] = NULL; | |
73 | ||
74 | info[PRN_END] = NULL; | |
5eaef520 | 75 | return info; |
cc5b487a | 76 | } |
77 | ||
28064364 | 78 | /* Function Name: GetPrnInfo |
cc5b487a | 79 | * Description: Stores the info in a queue. |
80 | * Arguments: name - name of the item to get information on. | |
81 | * Returns: a pointer to the first element in the queue or null | |
82 | * if printer not found. | |
83 | */ | |
84 | ||
28064364 | 85 | static struct mqelem *GetPrnInfo(char *name, int how) |
cc5b487a | 86 | { |
5eaef520 | 87 | int stat; |
600b459e | 88 | struct mqelem *elem = NULL; |
5eaef520 | 89 | |
28064364 | 90 | switch (how) |
91 | { | |
92 | case BY_NAME: | |
93 | stat = do_mr_query("get_printer", 1, &name, StoreInfo, &elem); | |
94 | if (stat == MR_NO_MATCH) | |
95 | { | |
96 | stat = do_mr_query("get_printer_by_duplexname", 1, &name, | |
97 | StoreInfo, &elem); | |
98 | } | |
99 | break; | |
100 | case BY_ETHERNET: | |
101 | stat = do_mr_query("get_printer_by_ethernet", 1, &name, | |
102 | StoreInfo, &elem); | |
103 | break; | |
104 | case BY_HOSTNAME: | |
105 | name = canonicalize_hostname(strdup(name)); | |
106 | stat = do_mr_query("get_printer_by_hostname", 1, &name, | |
107 | StoreInfo, &elem); | |
108 | free(name); | |
109 | break; | |
110 | case BY_RM: | |
111 | name = canonicalize_hostname(strdup(name)); | |
112 | stat = do_mr_query("get_printer_by_rm", 1, &name, | |
113 | StoreInfo, &elem); | |
114 | free(name); | |
115 | break; | |
116 | case BY_LOCATION: | |
117 | stat = do_mr_query("get_printer_by_location", 1, &name, | |
118 | StoreInfo, &elem); | |
119 | break; | |
120 | case BY_CONTACT: | |
121 | stat = do_mr_query("get_printer_by_contact", 1, &name, | |
122 | StoreInfo, &elem); | |
123 | break; | |
124 | } | |
125 | ||
126 | if (stat) | |
5eaef520 | 127 | { |
28064364 | 128 | com_err(program_name, stat, " in GetPrnInfo"); |
5eaef520 | 129 | return NULL; |
cc5b487a | 130 | } |
5eaef520 | 131 | return QueueTop(elem); |
cc5b487a | 132 | } |
133 | ||
28064364 | 134 | /* Function Name: PrintPrnInfo |
cc5b487a | 135 | * Description: Yet another specialized print function. |
136 | * Arguments: info - all info about this Printer. | |
7ac48069 | 137 | * Returns: printer name |
cc5b487a | 138 | */ |
139 | ||
28064364 | 140 | static char *PrintPrnInfo(char **info) |
cc5b487a | 141 | { |
28064364 | 142 | char buf[BUFSIZ], *hwaddr; |
143 | int status; | |
5eaef520 | 144 | |
145 | if (!info) /* If no informaion */ | |
146 | { | |
28064364 | 147 | Put_message("PrintPrnInfo called with null info!"); |
7ac48069 | 148 | return NULL; |
cc5b487a | 149 | } |
28064364 | 150 | Put_message(""); |
151 | sprintf(buf, "Printer: %-18s Duplex queue: %-18s", info[PRN_NAME], | |
152 | *info[PRN_DUPLEXNAME] ? info[PRN_DUPLEXNAME] : "[none]"); | |
153 | Put_message(buf); | |
154 | sprintf(buf, "Type: %-10s Hardware type: %-10s Hardware address: ", | |
155 | info[PRN_TYPE], info[PRN_HWTYPE]); | |
156 | status = do_mr_query("get_host_hwaddr", 1, &info[PRN_HOSTNAME], | |
157 | StoreHWAddr, &hwaddr); | |
158 | if (status == MR_SUCCESS) | |
159 | { | |
160 | strcat(buf, hwaddr); | |
161 | free(hwaddr); | |
162 | } | |
163 | else | |
164 | strcat(buf, "none"); | |
5eaef520 | 165 | Put_message(buf); |
28064364 | 166 | sprintf(buf, "Printer hostname: %s", info[PRN_HOSTNAME]); |
167 | Put_message(buf); | |
168 | sprintf(buf, "Printer log host: %s", info[PRN_LOGHOST]); | |
169 | Put_message(buf); | |
170 | sprintf(buf, "Spool host: %s", info[PRN_RM]); | |
171 | Put_message(buf); | |
172 | sprintf(buf, "Remote Printer Name: %s", info[PRN_RP]); | |
5eaef520 | 173 | Put_message(buf); |
174 | sprintf(buf, "Authentication: %-3s Price/page: %-3s Quota Server: %s", | |
28064364 | 175 | atoi(info[PRN_KA]) ? "yes" : "no", info[PRN_PC], info[PRN_RQ]); |
176 | Put_message(buf); | |
177 | sprintf(buf, "Restrict list: %-23s LPC ACL: %-23s", | |
178 | info[PRN_AC], info[PRN_LPC_ACL]); | |
5eaef520 | 179 | Put_message(buf); |
28064364 | 180 | sprintf(buf, "Location: %s", info[PRN_LOCATION]); |
5eaef520 | 181 | Put_message(buf); |
28064364 | 182 | sprintf(buf, "Contact: %s", info[PRN_CONTACT]); |
183 | Put_message(buf); | |
184 | sprintf(buf, MOD_FORMAT, info[PRN_MODBY], info[PRN_MODTIME], | |
185 | info[PRN_MODWITH]); | |
5eaef520 | 186 | Put_message(buf); |
7ac48069 | 187 | |
28064364 | 188 | return info[PRN_NAME]; |
cc5b487a | 189 | } |
190 | ||
28064364 | 191 | /* Function Name: AskPrnInfo. |
5eaef520 | 192 | * Description: This function askes the user for information about a |
cc5b487a | 193 | * printer and saves it into a structure. |
194 | * Arguments: info - a pointer the the structure to put the | |
28064364 | 195 | * info into. |
cc5b487a | 196 | * Returns: none. |
197 | */ | |
198 | ||
28064364 | 199 | static char **AskPrnInfo(char **info) |
cc5b487a | 200 | { |
5eaef520 | 201 | char temp_buf[BUFSIZ]; |
28064364 | 202 | char *args[3], *lpc_acl; |
203 | char *s, *d; | |
204 | int status; | |
5eaef520 | 205 | |
206 | Put_message(""); | |
28064364 | 207 | sprintf(temp_buf, "Printer entry for %s.", info[PRN_NAME]); |
5eaef520 | 208 | Put_message(temp_buf); |
209 | Put_message(""); | |
210 | ||
28064364 | 211 | if (GetTypeFromUser("Type of Printer", "printertype", &info[PRN_TYPE]) == |
212 | SUB_ERROR) | |
5eaef520 | 213 | return NULL; |
28064364 | 214 | if (GetTypeFromUser("Hardware Type", "printerhwtype", &info[PRN_HWTYPE]) == |
5eaef520 | 215 | SUB_ERROR) |
216 | return NULL; | |
28064364 | 217 | if (GetValueFromUser("Duplex spool name", &info[PRN_DUPLEXNAME]) == |
5eaef520 | 218 | SUB_ERROR) |
219 | return NULL; | |
28064364 | 220 | if (GetValueFromUser("Printer hostname (or [none])", &info[PRN_HOSTNAME]) == |
5eaef520 | 221 | SUB_ERROR) |
222 | return NULL; | |
28064364 | 223 | info[PRN_HOSTNAME] = canonicalize_hostname(info[PRN_HOSTNAME]); |
224 | if (GetValueFromUser("Log host", &info[PRN_LOGHOST]) == SUB_ERROR) | |
225 | return NULL; | |
226 | info[PRN_LOGHOST] = canonicalize_hostname(info[PRN_LOGHOST]); | |
227 | if (GetValueFromUser("Spool host (or [any])", &info[PRN_RM]) == SUB_ERROR) | |
228 | return NULL; | |
229 | info[PRN_RM] = canonicalize_hostname(info[PRN_RM]); | |
230 | if (GetValueFromUser("Remote printer name", &info[PRN_RP]) == SUB_ERROR) | |
231 | return NULL; | |
232 | if (GetValueFromUser("Quota server", &info[PRN_RQ]) == SUB_ERROR) | |
233 | return NULL; | |
234 | info[PRN_RQ] = canonicalize_hostname(info[PRN_RQ]); | |
235 | if (GetYesNoValueFromUser("Kerberos authenticated", &info[PRN_KA]) == | |
5eaef520 | 236 | SUB_ERROR) |
237 | return NULL; | |
28064364 | 238 | if (GetValueFromUser("Price per page", &info[PRN_PC]) == SUB_ERROR) |
5eaef520 | 239 | return NULL; |
28064364 | 240 | if (GetValueFromUser("Restrict list", &info[PRN_AC]) == SUB_ERROR) |
241 | return NULL; | |
242 | args[0] = info[PRN_TYPE]; | |
243 | args[1] = "LPC_ACL"; | |
244 | args[2] = "*"; | |
245 | status = do_mr_query("get_alias", 3, args, GetAliasValue, &lpc_acl); | |
246 | if (status == MR_SUCCESS) | |
247 | { | |
248 | free(info[PRN_LPC_ACL]); | |
249 | info[PRN_LPC_ACL] = lpc_acl; | |
250 | } | |
251 | if (GetValueFromUser("LPC ACL", &info[PRN_LPC_ACL]) == SUB_ERROR) | |
252 | return NULL; | |
253 | if (GetValueFromUser("Location", &info[PRN_LOCATION]) == SUB_ERROR) | |
254 | return NULL; | |
255 | if (GetValueFromUser("Contact", &info[PRN_CONTACT]) == SUB_ERROR) | |
5eaef520 | 256 | return NULL; |
257 | ||
28064364 | 258 | FreeAndClear(&info[PRN_MODTIME], TRUE); |
259 | FreeAndClear(&info[PRN_MODBY], TRUE); | |
260 | FreeAndClear(&info[PRN_MODWITH], TRUE); | |
5eaef520 | 261 | |
262 | return info; | |
cc5b487a | 263 | } |
264 | ||
265 | /* ---------------- Printer Menu ------------------ */ | |
266 | ||
28064364 | 267 | /* Function Name: GetPrn |
268 | * Description: Get Printer information | |
269 | * Arguments: argc, argv - name of printer in argv[1]. | |
cc5b487a | 270 | * Returns: DM_NORMAL. |
271 | */ | |
272 | ||
28064364 | 273 | int GetPrn(int argc, char **argv) |
cc5b487a | 274 | { |
600b459e | 275 | struct mqelem *top; |
cc5b487a | 276 | |
28064364 | 277 | top = GetPrnInfo(argv[1], BY_NAME); /* get info. */ |
278 | Loop(top, (void *) PrintPrnInfo); | |
5eaef520 | 279 | FreeQueue(top); /* clean the queue. */ |
280 | return DM_NORMAL; | |
cc5b487a | 281 | } |
282 | ||
28064364 | 283 | int GetPrnByEthernet(int argc, char **argv) |
284 | { | |
285 | struct mqelem *top; | |
286 | ||
287 | top = GetPrnInfo(argv[1], BY_ETHERNET); /* get info. */ | |
288 | Loop(top, (void *) PrintPrnInfo); | |
289 | FreeQueue(top); /* clean the queue. */ | |
290 | return DM_NORMAL; | |
291 | } | |
292 | ||
293 | int GetPrnByHostname(int argc, char **argv) | |
294 | { | |
295 | struct mqelem *top; | |
296 | ||
297 | top = GetPrnInfo(argv[1], BY_HOSTNAME); /* get info. */ | |
298 | Loop(top, (void *) PrintPrnInfo); | |
299 | FreeQueue(top); /* clean the queue. */ | |
300 | return DM_NORMAL; | |
301 | } | |
302 | ||
303 | int GetPrnByRM(int argc, char **argv) | |
304 | { | |
305 | struct mqelem *top; | |
306 | ||
307 | top = GetPrnInfo(argv[1], BY_RM); /* get info. */ | |
308 | Loop(top, (void *) PrintPrnInfo); | |
309 | FreeQueue(top); /* clean the queue. */ | |
310 | return DM_NORMAL; | |
311 | } | |
312 | ||
313 | int GetPrnByLocation(int argc, char **argv) | |
314 | { | |
315 | struct mqelem *top; | |
316 | ||
317 | top = GetPrnInfo(argv[1], BY_LOCATION); /* get info. */ | |
318 | Loop(top, (void *) PrintPrnInfo); | |
319 | FreeQueue(top); /* clean the queue. */ | |
320 | return DM_NORMAL; | |
321 | } | |
322 | ||
323 | int GetPrnByContact(int argc, char **argv) | |
324 | { | |
325 | struct mqelem *top; | |
326 | ||
327 | top = GetPrnInfo(argv[1], BY_CONTACT); /* get info. */ | |
328 | Loop(top, (void *) PrintPrnInfo); | |
329 | FreeQueue(top); /* clean the queue. */ | |
330 | return DM_NORMAL; | |
331 | } | |
332 | ||
333 | ||
334 | /* Function Name: RealDeletePrn | |
cc5b487a | 335 | * Description: Does the real deletion work. |
336 | * Arguments: info - array of char *'s containing all useful info. | |
5eaef520 | 337 | * one_item - a Boolean that is true if only one item |
cc5b487a | 338 | * in queue that dumped us here. |
339 | * Returns: none. | |
340 | */ | |
341 | ||
28064364 | 342 | void RealDeletePrn(char **info, Bool one_item) |
cc5b487a | 343 | { |
5eaef520 | 344 | int stat; |
cc5b487a | 345 | |
28064364 | 346 | if ((stat = do_mr_query("delete_printer", 1, &info[PRN_NAME], NULL, NULL))) |
347 | com_err(program_name, stat, " printer not deleted."); | |
5eaef520 | 348 | else |
28064364 | 349 | Put_message("Printer deleted."); |
cc5b487a | 350 | } |
351 | ||
28064364 | 352 | /* Function Name: DeletePrn |
353 | * Description: Delete a printer given its name. | |
cc5b487a | 354 | * Arguments: argc, argv - argv[1] is the name of the printer. |
355 | * Returns: none. | |
356 | */ | |
357 | ||
28064364 | 358 | int DeletePrn(int argc, char **argv) |
cc5b487a | 359 | { |
28064364 | 360 | struct mqelem *elem = GetPrnInfo(argv[1], BY_NAME); |
361 | QueryLoop(elem, PrintPrnInfo, RealDeletePrn, "Delete Printer"); | |
cc5b487a | 362 | |
5eaef520 | 363 | FreeQueue(elem); |
364 | return DM_NORMAL; | |
cc5b487a | 365 | } |
366 | ||
28064364 | 367 | /* Function Name: AddPrn |
368 | * Description: Add a printer | |
cc5b487a | 369 | * Arguments: arc, argv - name of printer in argv[1]. |
370 | * Returns: DM_NORMAL. | |
371 | */ | |
372 | ||
28064364 | 373 | int AddPrn(int argc, char **argv) |
cc5b487a | 374 | { |
5eaef520 | 375 | char *info[MAX_ARGS_SIZE], **args; |
376 | int stat; | |
377 | ||
378 | if (!ValidName(argv[1])) | |
379 | return DM_NORMAL; | |
380 | ||
28064364 | 381 | if (!(stat = do_mr_query("get_printer", 1, argv + 1, NULL, NULL)) || |
382 | !(stat = do_mr_query("get_printer_by_duplexname", 1, argv + 1, | |
7ac48069 | 383 | NULL, NULL))) |
5eaef520 | 384 | { |
385 | Put_message ("A Printer by that name already exists."); | |
386 | return DM_NORMAL; | |
387 | } | |
388 | else if (stat != MR_NO_MATCH) | |
389 | { | |
28064364 | 390 | com_err(program_name, stat, " in AddPrn"); |
5eaef520 | 391 | return DM_NORMAL; |
b7fbb301 | 392 | } |
cc5b487a | 393 | |
28064364 | 394 | args = AskPrnInfo(SetDefaults(info, argv[1])); |
5eaef520 | 395 | if (!args) |
396 | { | |
397 | Put_message("Aborted."); | |
398 | return DM_NORMAL; | |
399 | } | |
400 | ||
28064364 | 401 | if ((stat = do_mr_query("add_printer", CountArgs(args), args, NULL, NULL))) |
402 | com_err(program_name, stat, " in AddPrn"); | |
403 | ||
404 | if (stat == MR_SUCCESS && strcasecmp(info[PRN_HOSTNAME], "[NONE]")) | |
deb5d3ee | 405 | UpdateHWAddr(2, &info[PRN_HOSTNAME - 1]); |
cc5b487a | 406 | |
5eaef520 | 407 | FreeInfo(info); |
408 | return DM_NORMAL; | |
cc5b487a | 409 | } |
410 | ||
411 | ||
28064364 | 412 | /* Function Name: ChangePrn |
413 | * Description: Do the work of changing a Prn | |
f03f1f1b | 414 | * Arguments: argc, argv - printcap info |
5eaef520 | 415 | * Returns: |
f03f1f1b | 416 | */ |
417 | ||
28064364 | 418 | void ChangePrn(char **info, Bool one_item) |
f03f1f1b | 419 | { |
5eaef520 | 420 | int stat; |
421 | char **oldinfo; | |
422 | ||
423 | oldinfo = CopyInfo(info); | |
28064364 | 424 | if (!AskPrnInfo(info)) |
7ac48069 | 425 | return; |
28064364 | 426 | if ((stat = do_mr_query("delete_printer", 1, &info[PRN_NAME], NULL, NULL))) |
5eaef520 | 427 | { |
28064364 | 428 | com_err(program_name, stat, " printer not updated."); |
7ac48069 | 429 | return; |
f03f1f1b | 430 | } |
28064364 | 431 | if ((stat = do_mr_query("add_printer", CountArgs(info), info, NULL, NULL))) |
5eaef520 | 432 | { |
28064364 | 433 | com_err(program_name, stat, " in ChngPrn"); |
434 | if ((stat = do_mr_query("add_printer", CountArgs(oldinfo) - 3, | |
7ac48069 | 435 | oldinfo, NULL, NULL))) |
5eaef520 | 436 | com_err(program_name, stat, " while attempting to put old info back"); |
b98304a9 | 437 | } |
5eaef520 | 438 | FreeInfo(oldinfo); |
7ac48069 | 439 | return; |
f03f1f1b | 440 | } |
441 | ||
442 | ||
28064364 | 443 | /* Function Name: ChngPrn |
f03f1f1b | 444 | * Description: Update the printcap information |
445 | * Arguments: argc, argv - name of printer in argv[1]. | |
446 | * Returns: DM_NORMAL. | |
447 | */ | |
448 | ||
28064364 | 449 | int ChngPrn(int argc, char **argv) |
f03f1f1b | 450 | { |
28064364 | 451 | struct mqelem *elem = GetPrnInfo(argv[1], BY_NAME); |
452 | QueryLoop(elem, NullPrint, ChangePrn, "Change the printer"); | |
5eaef520 | 453 | FreeQueue(elem); |
454 | return DM_NORMAL; | |
f03f1f1b | 455 | } |
1b2e1580 | 456 | |
457 | ||
28064364 | 458 | int UpdateHWAddr(int argc, char **argv) |
1b2e1580 | 459 | { |
5eaef520 | 460 | int stat; |
28064364 | 461 | char *name, *hwaddr, *s, *d, *uargv[2]; |
1b2e1580 | 462 | |
28064364 | 463 | name = canonicalize_hostname(strdup(argv[1])); |
464 | stat = do_mr_query("get_host_hwaddr", 1, &name, StoreHWAddr, &hwaddr); | |
465 | if (stat != MR_SUCCESS) | |
5eaef520 | 466 | { |
28064364 | 467 | free(name); |
468 | com_err(program_name, stat, " checking host ethernet address"); | |
5eaef520 | 469 | return DM_NORMAL; |
1b2e1580 | 470 | } |
471 | ||
28064364 | 472 | if (GetValueFromUser("Hardware ethernet address", &hwaddr) == SUB_ERROR) |
5eaef520 | 473 | { |
28064364 | 474 | free(name); |
5eaef520 | 475 | return DM_NORMAL; |
b7fbb301 | 476 | } |
1b2e1580 | 477 | |
28064364 | 478 | s = d = hwaddr; |
479 | do | |
5eaef520 | 480 | { |
28064364 | 481 | if (*s != ':') |
482 | *d++ = *s; | |
1b2e1580 | 483 | } |
28064364 | 484 | while (*s++); |
1b2e1580 | 485 | |
28064364 | 486 | uargv[0] = name; |
487 | uargv[1] = hwaddr; | |
488 | if ((stat = do_mr_query("update_host_hwaddr", 2, uargv, NULL, NULL))) | |
489 | com_err(program_name, stat, " updating ethernet address."); | |
5eaef520 | 490 | |
28064364 | 491 | free(name); |
492 | free(hwaddr); | |
5eaef520 | 493 | return DM_NORMAL; |
1b2e1580 | 494 | } |