1 /* SmoothWall libsmooth.
3 * This program is distributed under the terms of the GNU General Public
4 * Licence. See the file COPYING for details.
6 * (c) Lawrence Manning, 2001
7 * Contains network library functions.
11 #include "libsmooth.h"
19 extern struct nic nics
[];
20 extern struct knic knics
[];
22 int scanned_nics_read_done
= 0;
24 newtComponent networkform
;
25 newtComponent addressentry
;
26 newtComponent netmaskentry
;
27 newtComponent statictyperadio
;
28 newtComponent dhcptyperadio
;
29 newtComponent pppoetyperadio
;
30 newtComponent pptptyperadio
;
31 newtComponent dhcphostnameentry
;
33 /* acceptable character filter for IP and netmaks entry boxes */
34 static int ip_input_filter(newtComponent entry
, void * data
, int ch
, int cursor
)
36 if ((ch
>= '0' && ch
<= '9') || ch
== '.' || ch
== '\r' || ch
>= NEWT_KEY_EXTRA_BASE
)
41 /* This is a groovie dialog for showing network info. Takes a keyvalue list,
42 * a colour and a dhcp flag. Shows the current settings, and rewrites them
43 * if necessary. DHCP flag sets wether to show the dhcp checkbox. */
44 int changeaddress(struct keyvalue
*kv
, char *colour
, int typeflag
,
45 char *defaultdhcphostname
)
49 char *dhcphostnameresult
;
50 struct newtExitStruct es
;
52 newtComponent addresslabel
;
53 newtComponent netmasklabel
;
54 newtComponent dhcphostnamelabel
;
55 newtComponent ok
, cancel
;
57 char temp
[STRING_SIZE
];
58 char addressfield
[STRING_SIZE
];
59 char netmaskfield
[STRING_SIZE
];
60 char typefield
[STRING_SIZE
];
61 char dhcphostnamefield
[STRING_SIZE
];
64 char type
[STRING_SIZE
];
65 int startstatictype
= 0;
66 int startdhcptype
= 0;
67 int startpppoetype
= 0;
68 int startpptptype
= 0;
70 /* Build some key strings. */
71 sprintf(addressfield
, "%s_ADDRESS", colour
);
72 sprintf(netmaskfield
, "%s_NETMASK", colour
);
73 sprintf(typefield
, "%s_TYPE", colour
);
74 sprintf(dhcphostnamefield
, "%s_DHCP_HOSTNAME", colour
);
76 sprintf(message
, ctr
[TR_INTERFACE
], colour
);
77 newtCenteredWindow(44, (typeflag
? 18 : 12), message
);
79 networkform
= newtForm(NULL
, NULL
, 0);
81 sprintf(message
, ctr
[TR_ENTER_THE_IP_ADDRESS_INFORMATION
], colour
);
82 header
= newtTextboxReflowed(1, 1, message
, 42, 0, 0, 0);
83 newtFormAddComponent(networkform
, header
);
85 /* See if we need a dhcp checkbox. If we do, then we shift the contents
86 * of the window down two rows to make room. */
89 strcpy(temp
, "STATIC"); findkey(kv
, typefield
, temp
);
90 if (strcmp(temp
, "STATIC") == 0) startstatictype
= 1;
91 if (strcmp(temp
, "DHCP") == 0) startdhcptype
= 1;
92 if (strcmp(temp
, "PPPOE") == 0) startpppoetype
= 1;
93 if (strcmp(temp
, "PPTP") == 0) startpptptype
= 1;
94 statictyperadio
= newtRadiobutton(2, 4, ctr
[TR_STATIC
], startstatictype
, NULL
);
95 dhcptyperadio
= newtRadiobutton(2, 5, "DHCP", startdhcptype
, statictyperadio
);
96 pppoetyperadio
= newtRadiobutton(2, 6, "PPPOE", startpppoetype
, dhcptyperadio
);
97 pptptyperadio
= newtRadiobutton(2, 7, "PPTP", startpptptype
, pppoetyperadio
);
98 newtFormAddComponents(networkform
, statictyperadio
, dhcptyperadio
,
99 pppoetyperadio
, pptptyperadio
, NULL
);
100 newtComponentAddCallback(statictyperadio
, networkdialogcallbacktype
, NULL
);
101 newtComponentAddCallback(dhcptyperadio
, networkdialogcallbacktype
, NULL
);
102 newtComponentAddCallback(pppoetyperadio
, networkdialogcallbacktype
, NULL
);
103 newtComponentAddCallback(pptptyperadio
, networkdialogcallbacktype
, NULL
);
104 dhcphostnamelabel
= newtTextbox(2, 9, 18, 1, 0);
105 newtTextboxSetText(dhcphostnamelabel
, ctr
[TR_DHCP_HOSTNAME
]);
106 strcpy(temp
, defaultdhcphostname
);
107 findkey(kv
, dhcphostnamefield
, temp
);
108 dhcphostnameentry
= newtEntry(20, 9, temp
, 20, &dhcphostnameresult
, 0);
109 newtFormAddComponent(networkform
, dhcphostnamelabel
);
110 newtFormAddComponent(networkform
, dhcphostnameentry
);
111 if (startdhcptype
== 0)
112 newtEntrySetFlags(dhcphostnameentry
, NEWT_FLAG_DISABLED
, NEWT_FLAGS_SET
);
115 addresslabel
= newtTextbox(2, (typeflag
? 11 : 4) + 0, 18, 1, 0);
116 newtTextboxSetText(addresslabel
, ctr
[TR_IP_ADDRESS_PROMPT
]);
118 findkey(kv
, addressfield
, temp
);
119 addressentry
= newtEntry(20, (typeflag
? 11 : 4) + 0, temp
, 20, &addressresult
, 0);
120 newtEntrySetFilter(addressentry
, ip_input_filter
, NULL
);
121 if (typeflag
== 1 && startstatictype
== 0 && startpptptype
== 0 )
122 newtEntrySetFlags(addressentry
, NEWT_FLAG_DISABLED
, NEWT_FLAGS_SET
);
123 newtFormAddComponent(networkform
, addresslabel
);
124 newtFormAddComponent(networkform
, addressentry
);
127 netmasklabel
= newtTextbox(2, (typeflag
? 11 : 4) + 1, 18, 1, 0);
128 newtTextboxSetText(netmasklabel
, ctr
[TR_NETMASK_PROMPT
]);
129 strcpy(temp
, "255.255.255.0"); findkey(kv
, netmaskfield
, temp
);
130 netmaskentry
= newtEntry(20, (typeflag
? 11 : 4) + 1, temp
, 20, &netmaskresult
, 0);
131 newtEntrySetFilter(netmaskentry
, ip_input_filter
, NULL
);
132 if (typeflag
== 1 && startstatictype
== 0 && startpptptype
== 0 )
133 newtEntrySetFlags(netmaskentry
, NEWT_FLAG_DISABLED
, NEWT_FLAGS_SET
);
135 newtFormAddComponent(networkform
, netmasklabel
);
136 newtFormAddComponent(networkform
, netmaskentry
);
139 ok
= newtButton(8, (typeflag
? 14 : 7), ctr
[TR_OK
]);
140 cancel
= newtButton(26, (typeflag
? 14 : 7), ctr
[TR_CANCEL
]);
142 newtFormAddComponents(networkform
, ok
, cancel
, NULL
);
145 newtDrawForm(networkform
);
150 newtFormRun(networkform
, &es
);
154 /* OK was pressed; verify the contents of each entry. */
155 strcpy(message
, ctr
[TR_INVALID_FIELDS
]);
157 strcpy(type
, "STATIC");
160 if (strcmp(type
, "STATIC") == 0 || strcmp(type
, "PPTP") == 0 )
162 if (inet_addr(addressresult
) == INADDR_NONE
)
164 strcat(message
, ctr
[TR_IP_ADDRESS_CR
]);
167 if (inet_addr(netmaskresult
) == INADDR_NONE
)
169 strcat(message
, ctr
[TR_NETWORK_MASK_CR
]);
173 if (strcmp(type
, "DHCP") == 0)
175 if (!strlen(dhcphostnameresult
))
177 strcat(message
, ctr
[TR_DHCP_HOSTNAME_CR
]);
185 /* No errors! Set new values, depending on dhcp flag etc. */
188 replacekeyvalue(kv
, dhcphostnamefield
, dhcphostnameresult
);
189 if (strcmp(type
, "STATIC") != 0 && strcmp(type
, "PPTP") != 0)
191 replacekeyvalue(kv
, addressfield
, "0.0.0.0");
192 replacekeyvalue(kv
, netmaskfield
, "0.0.0.0");
196 replacekeyvalue(kv
, addressfield
, addressresult
);
197 replacekeyvalue(kv
, netmaskfield
, netmaskresult
);
199 replacekeyvalue(kv
, typefield
, type
);
203 replacekeyvalue(kv
, addressfield
, addressresult
);
204 replacekeyvalue(kv
, netmaskfield
, netmaskresult
);
207 setnetaddress(kv
, colour
);
214 newtFormDestroy(networkform
);
220 /* for pppoe: return string thats type STATIC, DHCP or PPPOE */
221 int gettype(char *type
)
223 newtComponent selected
= newtRadioGetCurrent(statictyperadio
);
225 if (selected
== statictyperadio
)
226 strcpy(type
, "STATIC");
227 else if (selected
== dhcptyperadio
)
228 strcpy(type
, "DHCP");
229 else if (selected
== pppoetyperadio
)
230 strcpy(type
, "PPPOE");
231 else if (selected
== pptptyperadio
)
232 strcpy(type
, "PPTP");
234 strcpy(type
, "ERROR");
239 /* 0.9.9: calculates broadcast too. */
240 int setnetaddress(struct keyvalue
*kv
, char *colour
)
242 char addressfield
[STRING_SIZE
];
243 char netaddressfield
[STRING_SIZE
];
244 char netmaskfield
[STRING_SIZE
];
245 char broadcastfield
[STRING_SIZE
];
246 char address
[STRING_SIZE
];
247 char netmask
[STRING_SIZE
];
248 unsigned long int intaddress
;
249 unsigned long int intnetaddress
;
250 unsigned long int intnetmask
;
251 unsigned long int intbroadcast
;
256 /* Build some key strings. */
257 sprintf(addressfield
, "%s_ADDRESS", colour
);
258 sprintf(netaddressfield
, "%s_NETADDRESS", colour
);
259 sprintf(netmaskfield
, "%s_NETMASK", colour
);
260 sprintf(broadcastfield
, "%s_BROADCAST", colour
);
262 strcpy(address
, ""); findkey(kv
, addressfield
, address
);
263 strcpy(netmask
, ""); findkey(kv
, netmaskfield
, netmask
);
265 /* Calculate netaddress. Messy.. */
266 intaddress
= inet_addr(address
);
267 intnetmask
= inet_addr(netmask
);
269 intnetaddress
= intaddress
& intnetmask
;
270 temp
.s_addr
= intnetaddress
;
271 netaddress
= inet_ntoa(temp
);
273 replacekeyvalue(kv
, netaddressfield
, netaddress
);
275 intbroadcast
= intnetaddress
| ~intnetmask
;
276 temp
.s_addr
= intbroadcast
;
277 broadcast
= inet_ntoa(temp
);
279 replacekeyvalue(kv
, broadcastfield
, broadcast
);
284 /* Called when dhcp flag is toggled. Toggle disabled state of other 3
286 void networkdialogcallbacktype(newtComponent cm
, void *data
)
288 char type
[STRING_SIZE
];
292 if (strcmp(type
, "STATIC") != 0 && strcmp(type
, "PPTP") != 0 )
294 newtEntrySetFlags(addressentry
, NEWT_FLAG_DISABLED
, NEWT_FLAGS_SET
);
295 newtEntrySetFlags(netmaskentry
, NEWT_FLAG_DISABLED
, NEWT_FLAGS_SET
);
299 newtEntrySetFlags(addressentry
, NEWT_FLAG_DISABLED
, NEWT_FLAGS_RESET
);
300 newtEntrySetFlags(netmaskentry
, NEWT_FLAG_DISABLED
, NEWT_FLAGS_RESET
);
302 if (strcmp(type
, "DHCP") == 0)
303 newtEntrySetFlags(dhcphostnameentry
, NEWT_FLAG_DISABLED
, NEWT_FLAGS_RESET
);
305 newtEntrySetFlags(dhcphostnameentry
, NEWT_FLAG_DISABLED
, NEWT_FLAGS_SET
);
308 newtDrawForm(networkform
);
311 int interfacecheck(struct keyvalue
*kv
, char *colour
)
313 char temp
[STRING_SIZE
];
314 char colourfields
[NETCHANGE_TOTAL
][STRING_SIZE
];
317 sprintf(colourfields
[ADDRESS
], "%s_ADDRESS", colour
);
318 sprintf(colourfields
[NETADDRESS
], "%s_NETADDRESS", colour
);
319 sprintf(colourfields
[NETMASK
], "%s_NETMASK", colour
);
321 for (c
= 0; c
< 3; c
++)
323 strcpy(temp
, ""); findkey(kv
, colourfields
[c
], temp
);
324 if (!(strlen(temp
))) return 0;
329 /* Funky routine for loading all drivers (cept those are already loaded.). */
330 int probecards(char *driver
, char *driveroptions
)
335 /* ### alter strupper ###
336 char *strupper(char *s)
339 for (n=0;s[n];n++) s[n]=toupper(s[n]);
344 /* neuer StringUpper, wird zur Zeit nicht benutzt da UTF-8 nicht geht.
345 void strupper(unsigned char *string)
348 for (str = string; *str != '\0'; str++)
349 if (!(*str & 0x80) && islower(*str))
350 *str = toupper(*str);
354 int write_configs_netudev(char *description
, char *macaddr
, char *colour
)
356 #define UDEV_NET_CONF "/etc/udev/rules.d/30-persistent-network.rules"
358 char commandstring
[STRING_SIZE
];
359 struct keyvalue
*kv
= initkeyvalues();
360 char temp1
[STRING_SIZE
], temp2
[STRING_SIZE
], temp3
[STRING_SIZE
];
361 char ucolour
[STRING_SIZE
];
363 // sprintf(ucolour, colour);
364 // strupper(ucolour);
368 case 'g': sprintf(ucolour
, "GREEN");
369 strcpy(knics
[_GREEN_CARD_
].description
, description
);
370 strcpy(knics
[_GREEN_CARD_
].macaddr
, macaddr
);
372 case 'r': sprintf(ucolour
, "RED");
373 strcpy(knics
[_RED_CARD_
].description
, description
);
374 strcpy(knics
[_RED_CARD_
].macaddr
, macaddr
);
376 case 'o': sprintf(ucolour
, "ORANGE");
377 strcpy(knics
[_ORANGE_CARD_
].description
, description
);
378 strcpy(knics
[_ORANGE_CARD_
].macaddr
, macaddr
);
380 case 'b': sprintf(ucolour
, "BLUE");
381 strcpy(knics
[_BLUE_CARD_
].description
, description
);
382 strcpy(knics
[_BLUE_CARD_
].macaddr
, macaddr
);
384 default: sprintf(ucolour
, "DUMMY");
388 if (!(readkeyvalues(kv
, CONFIG_ROOT
"/ethernet/settings")))
391 errorbox(ctr
[TR_UNABLE_TO_OPEN_SETTINGS_FILE
]);
395 sprintf(temp1
, "%s_DEV", ucolour
);
396 sprintf(temp2
, "%s_MACADDR", ucolour
);
397 sprintf(temp3
, "%s0", colour
);
398 replacekeyvalue(kv
, temp1
, temp3
);
399 replacekeyvalue(kv
, temp2
, macaddr
);
400 sprintf(temp1
, "%s_DESCRIPTION", ucolour
);
401 replacekeyvalue(kv
, temp1
, description
);
403 writekeyvalues(kv
, CONFIG_ROOT
"/ethernet/settings");
406 // Make sure that there is no conflict
407 snprintf(commandstring
, STRING_SIZE
, "/usr/bin/touch "UDEV_NET_CONF
" >/dev/null 2>&1");
408 system(commandstring
);
410 snprintf(commandstring
, STRING_SIZE
, "/bin/cat "UDEV_NET_CONF
" | /bin/grep -v \"%s\" > "UDEV_NET_CONF
" 2>/dev/null", macaddr
);
411 system(commandstring
);
413 snprintf(commandstring
, STRING_SIZE
, "/bin/cat "UDEV_NET_CONF
" | /bin/grep -v \"%s\" > "UDEV_NET_CONF
" 2>/dev/null", colour
);
414 system(commandstring
);
416 if( (fp
= fopen(UDEV_NET_CONF
, "a")) == NULL
)
418 fprintf(stderr
,"Couldn't open" UDEV_NET_CONF
);
421 fprintf(fp
,"ACTION==\"add\", SUBSYSTEM==\"net\", SYSFS{address}==\"%s\", NAME=\"%s0\" # %s\n", macaddr
, colour
, description
);
427 int scan_network_cards(void)
430 char description
[STRING_SIZE
], macaddr
[STRING_SIZE
], temp_line
[STRING_SIZE
];
433 if (!(scanned_nics_read_done
))
435 fprintf(flog
,"Enter scan_network_cards\n"); // #### Debug ####
436 mysystem("/bin/probenic.sh");
437 // Read our scanned nics
438 if( (fp
= fopen(SCANNED_NICS
, "r")) == NULL
)
440 fprintf(stderr
,"Couldn't open "SCANNED_NICS
);
443 while (fgets(temp_line
, STRING_SIZE
, fp
) != NULL
)
445 strcpy(description
, strtok(temp_line
,";"));
446 strcpy(macaddr
, strtok(NULL
,";"));
447 if ( strlen(macaddr
) ) {
448 strcpy(nics
[count
].description
, description
);
449 strcpy(nics
[count
].macaddr
, macaddr
);
455 scanned_nics_read_done
= 1;
461 int nicmenu(char *colour
)
463 int rc
, choise
= 0, count
= 0, kcount
= 0, mcount
= 0, i
, j
, nic_in_use
;
464 int found_NIC_as_Card
[4];
465 char message
[STRING_SIZE
];
467 char cMenuInhalt
[STRING_SIZE
];
468 char MenuInhalt
[20][180];
469 char *pMenuInhalt
[20];
471 // strcpy( message , pnics[count].macaddr);
472 // while (strcmp(message, "")) {
474 // strcpy( message , pnics[count].macaddr);
477 while (strcmp(nics
[count
].macaddr
, "")) count
++; // 2 find how many nics in system
478 for ( i
=0 ; i
<4;i
++) if (strcmp(knics
[i
].macaddr
, "")) kcount
++; // loop to find all knowing nics
479 fprintf(flog
, "Enter NicMenu\n"); // #### Debug ####
480 fprintf(flog
, "count nics %i\ncount knics %i\n", count
, kcount
); // #### Debug ####
482 // If new nics are found...
483 if (count
> kcount
) {
484 for (i
=0 ; i
< count
; i
++)
487 for (j
=0 ; j
<= kcount
; j
++) {
488 if (strcmp(nics
[ i
].macaddr
, knics
[ j
].macaddr
) == 0 ) {
490 fprintf(flog
,"NIC \"%s\" is in use.\n", nics
[ i
].macaddr
); // #### Debug ####
495 fprintf(flog
,"NIC \"%s\" is free.\n", nics
[ i
].macaddr
); // #### Debug ####
496 if ( strlen(nics
[i
].description
) < 55 )
497 sprintf(MenuInhalt
[mcount
], "%.*s", strlen(nics
[i
].description
)-2, nics
[i
].description
+1);
499 sprintf(cMenuInhalt
, "%.50s", nics
[i
].description
+ 1);
500 strncpy(MenuInhalt
[mcount
], cMenuInhalt
,(strrchr(cMenuInhalt
,' ') - cMenuInhalt
));
501 strcat (MenuInhalt
[mcount
], "...");
504 while ( strlen(MenuInhalt
[mcount
]) < 50) strcat(MenuInhalt
[mcount
], " "); // Fill with space.
506 strcat(MenuInhalt
[mcount
], " (");
507 strcat(MenuInhalt
[mcount
], nics
[i
].macaddr
);
508 strcat(MenuInhalt
[mcount
], ")");
509 pMenuInhalt
[mcount
] = MenuInhalt
[mcount
];
510 found_NIC_as_Card
[mcount
]=i
;
515 pMenuInhalt
[mcount
] = NULL
;
517 // sprintf(message, "Es wurde(n) %d freie Netzwerkkarte(n) in Ihrem System gefunden.\nBitte waehlen Sie im naechsten Dialog eine davon aus.\n", count);
518 // newtWinMessage("NetcardMenu", ctr[TR_OK], message);
520 sprintf(message
, "(TR) Bitte waehlen Sie eine der untenstehenden Netzwerkkarten fuer die Schnittstelle \"%s\" aus.\n", colour
);
521 rc
= newtWinMenu("(TR) NetcardMenu2", message
, 50, 5, 5, 6, pMenuInhalt
, &choise
, ctr
[TR_OK
], ctr
[TR_SELECT
], ctr
[TR_CANCEL
], NULL
);
523 if ( rc
== 0 || rc
== 1) {
524 write_configs_netudev(nics
[choise
].description
, nics
[found_NIC_as_Card
[choise
]].macaddr
, colour
);
525 } else if (rc
== 2) {
526 // manualdriver("pcnet32","");
530 // We have to add here that you can manually add a device
531 errorbox("(TR) Es wurden leider keine freien Netzwerkkarten fuer die Schnittstelle in ihrem System gefunden.");
536 int remove_nic_entry(char *colour
)
538 struct keyvalue
*kv
= initkeyvalues();
539 char message
[STRING_SIZE
];
540 char temp1
[STRING_SIZE
], temp2
[STRING_SIZE
];
541 char ucolour
[STRING_SIZE
];
545 if (!(readkeyvalues(kv
, CONFIG_ROOT
"/ethernet/settings")))
548 errorbox(ctr
[TR_UNABLE_TO_OPEN_SETTINGS_FILE
]);
554 case 'g': sprintf(ucolour
, "GREEN");
555 strcpy(knics
[_GREEN_CARD_
].description
, ctr
[TR_UNSET
]);
556 strcpy(knics
[_GREEN_CARD_
].macaddr
, "");
557 strcpy(knics
[_GREEN_CARD_
].colour
, "");
559 case 'r': sprintf(ucolour
, "RED");
560 strcpy(knics
[_RED_CARD_
].description
, ctr
[TR_UNSET
]);
561 strcpy(knics
[_RED_CARD_
].macaddr
, "");
562 strcpy(knics
[_RED_CARD_
].colour
, "");
564 case 'o': sprintf(ucolour
, "ORANGE");
565 strcpy(knics
[_ORANGE_CARD_
].description
, ctr
[TR_UNSET
]);
566 strcpy(knics
[_ORANGE_CARD_
].macaddr
, "");
567 strcpy(knics
[_ORANGE_CARD_
].colour
, "");
569 case 'b': sprintf(ucolour
, "BLUE");
570 strcpy(knics
[_BLUE_CARD_
].description
, ctr
[TR_UNSET
]);
571 strcpy(knics
[_BLUE_CARD_
].macaddr
, "");
572 strcpy(knics
[_BLUE_CARD_
].colour
, "");
574 default: sprintf(ucolour
, "DUMMY");
578 sprintf(message
, "(TR) Soll die Netzwerkkarte \"%s\" entfernt werden ?\n", colour
);
579 rc
= newtWinChoice(ctr
[TR_WARNING
], ctr
[TR_OK
], ctr
[TR_CANCEL
], message
);
581 if ( rc
= 0 || rc
== 1) {
582 sprintf(temp1
, "%s_DEV", ucolour
);
583 sprintf(temp2
, "%s_MACADDR", ucolour
);
584 replacekeyvalue(kv
, temp1
, "");
585 replacekeyvalue(kv
, temp2
, "");
586 sprintf(temp1
, "%s_DESCRIPTION", ucolour
);
587 replacekeyvalue(kv
, temp1
, "");
589 writekeyvalues(kv
, CONFIG_ROOT
"/ethernet/settings");
596 /* Manual entry for gurus. */
597 int manualdriver(char *driver
, char *driveroptions
)
599 char *values
[] = { NULL
, NULL
}; /* pointers for the values. */
600 struct newtWinEntry entries
[] =
601 { { "", &values
[0], 0,}, { NULL
, NULL
, 0 } };
603 char commandstring
[STRING_SIZE
];
607 strcpy(driveroptions
, "");
609 rc
= newtWinEntries(ctr
[TR_SELECT_NETWORK_DRIVER
],
610 ctr
[TR_MODULE_PARAMETERS
], 50, 5, 5, 40, entries
,
611 ctr
[TR_OK
], ctr
[TR_CANCEL
], NULL
);
612 if (rc
== 0 || rc
== 1)
614 if (strlen(values
[0]))
616 sprintf(commandstring
, "/sbin/modprobe %s", values
[0]);
617 if (runcommandwithstatus(commandstring
, ctr
[TR_LOADING_MODULE
]) == 0)
619 if ((driverend
= strchr(values
[0], ' ')))
622 strcpy(driver
, values
[0]);
623 strcpy(driveroptions
, driverend
+ 1);
627 strcpy(driver
, values
[0]);
628 strcpy(driveroptions
, "");
632 errorbox(ctr
[TR_UNABLE_TO_LOAD_DRIVER_MODULE
]);
635 errorbox(ctr
[TR_MODULE_NAME_CANNOT_BE_BLANK
]);