/[rdesktop]/jpeg/rdesktop/trunk/rdesktop.c
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Annotation of /jpeg/rdesktop/trunk/rdesktop.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1255 - (hide annotations)
Sun Sep 17 11:04:50 2006 UTC (17 years, 9 months ago) by stargo
Original Path: sourceforge.net/trunk/rdesktop/rdesktop.c
File MIME type: text/plain
File size: 33873 byte(s)
allow multiple sound-drivers to be compiled in simultaneously and
make the runtime selectable

1 forsberg 350 /* -*- c-basic-offset: 8 -*-
2 matty 10 rdesktop: A Remote Desktop Protocol client.
3     Entrypoint and utility functions
4 stargo 828 Copyright (C) Matthew Chapman 1999-2005
5 jsorg71 100
6 matty 10 This program is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation; either version 2 of the License, or
9     (at your option) any later version.
10 jsorg71 100
11 matty 10 This program is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14     GNU General Public License for more details.
15 jsorg71 100
16 matty 10 You should have received a copy of the GNU General Public License
17     along with this program; if not, write to the Free Software
18     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19     */
20    
21 matty 30 #include <stdarg.h> /* va_list va_start va_end */
22 matty 24 #include <unistd.h> /* read close getuid getgid getpid getppid gethostname */
23     #include <fcntl.h> /* open */
24     #include <pwd.h> /* getpwuid */
25 matthewc 211 #include <termios.h> /* tcgetattr tcsetattr */
26 matty 24 #include <sys/stat.h> /* stat */
27     #include <sys/time.h> /* gettimeofday */
28     #include <sys/times.h> /* times */
29 stargo 570 #include <ctype.h> /* toupper */
30 astrand 325 #include <errno.h>
31 matty 10 #include "rdesktop.h"
32    
33 stargo 857 #ifdef HAVE_LOCALE_H
34 stargo 855 #include <locale.h>
35 stargo 857 #endif
36 astrand 962 #ifdef HAVE_ICONV
37 stargo 857 #ifdef HAVE_LANGINFO_H
38 stargo 855 #include <langinfo.h>
39     #endif
40 stargo 857 #endif
41 stargo 855
42 matthewc 220 #ifdef EGD_SOCKET
43 stargo 881 #include <sys/types.h>
44 matthewc 220 #include <sys/socket.h> /* socket connect */
45     #include <sys/un.h> /* sockaddr_un */
46     #endif
47    
48     #include <openssl/md5.h>
49    
50 astrand 479 char g_title[64] = "";
51     char g_username[64];
52 jsorg71 710 char g_hostname[16];
53 astrand 975 char g_keymapname[PATH_MAX] = "";
54 astrand 1035 unsigned int g_keylayout = 0x409; /* Defaults to US keyboard layout */
55 astrand 964 int g_keyboard_type = 0x4; /* Defaults to US keyboard layout */
56     int g_keyboard_subtype = 0x0; /* Defaults to US keyboard layout */
57     int g_keyboard_functionkeys = 0xc; /* Defaults to US keyboard layout */
58 astrand 500
59     int g_width = 800; /* width is special: If 0, the
60     geometry will be fetched from
61     _NET_WORKAREA. If negative,
62     absolute value specifies the
63     percent of the whole screen. */
64 jsorg71 447 int g_height = 600;
65 stargo 800 int g_xpos = 0;
66     int g_ypos = 0;
67 stargo 867 int g_pos = 0; /* 0 position unspecified,
68     1 specified,
69     2 xpos neg,
70     4 ypos neg */
71 jsorg71 710 extern int g_tcp_port_rdp;
72 astrand 1226 int g_server_depth = -1;
73 jsorg71 450 int g_win_button_size = 0; /* If zero, disable single app mode */
74 jsorg71 437 BOOL g_bitmap_compression = True;
75 jsorg71 447 BOOL g_sendmotion = True;
76 jsorg71 678 BOOL g_bitmap_cache = True;
77 jsorg71 725 BOOL g_bitmap_cache_persist_enable = False;
78     BOOL g_bitmap_cache_precache = True;
79 jsorg71 437 BOOL g_encryption = True;
80 forsberg 427 BOOL packet_encryption = True;
81 jsorg71 848 BOOL g_desktop_save = True; /* desktop save order */
82     BOOL g_polygon_ellipse_orders = True; /* polygon / ellipse orders */
83 jsorg71 447 BOOL g_fullscreen = False;
84 jsorg71 450 BOOL g_grab_keyboard = True;
85     BOOL g_hide_decorations = False;
86 astrand 458 BOOL g_use_rdp5 = True;
87 ossman_ 1207 BOOL g_rdpclip = True;
88 matthewc 482 BOOL g_console_session = False;
89 astrand 552 BOOL g_numlock_sync = False;
90 astrand 1053 BOOL lspci_enabled = False;
91 stargo 648 BOOL g_owncolmap = False;
92 astrand 651 BOOL g_ownbackstore = True; /* We can't rely on external BackingStore */
93 astrand 1199 BOOL g_seamless_rdp = False;
94 stargo 648 uint32 g_embed_wnd;
95 astrand 651 uint32 g_rdp5_performanceflags =
96     RDP5_NO_WALLPAPER | RDP5_NO_FULLWINDOWDRAG | RDP5_NO_MENUANIMATIONS;
97 astrand 977 /* Session Directory redirection */
98     BOOL g_redirect = False;
99     char g_redirect_server[64];
100     char g_redirect_domain[16];
101     char g_redirect_password[64];
102     char g_redirect_username[64];
103     char g_redirect_cookie[128];
104     uint32 g_redirect_flags = 0;
105 matty 10
106 stargo 501 #ifdef WITH_RDPSND
107 matthewc 520 BOOL g_rdpsnd = False;
108 stargo 501 #endif
109    
110 stargo 855 #ifdef HAVE_ICONV
111     char g_codepage[16] = "";
112     #endif
113    
114 n-ki 569 extern RDPDR_DEVICE g_rdpdr_device[];
115     extern uint32 g_num_devices;
116 astrand 651 extern char *g_rdpdr_clientname;
117 n-ki 569
118 astrand 333 #ifdef RDP2VNC
119     extern int rfb_port;
120     extern int defer_time;
121     void
122     rdp2vnc_connect(char *server, uint32 flags, char *domain, char *password,
123     char *shell, char *directory);
124     #endif
125 matty 10 /* Display usage information */
126 matty 25 static void
127     usage(char *program)
128 matty 10 {
129 matthewc 122 fprintf(stderr, "rdesktop: A Remote Desktop Protocol client.\n");
130 stargo 828 fprintf(stderr, "Version " VERSION ". Copyright (C) 1999-2005 Matt Chapman.\n");
131 matthewc 122 fprintf(stderr, "See http://www.rdesktop.org/ for more information.\n\n");
132    
133 matthewc 222 fprintf(stderr, "Usage: %s [options] server[:port]\n", program);
134 astrand 333 #ifdef RDP2VNC
135     fprintf(stderr, " -V: vnc port\n");
136 forsberg 471 fprintf(stderr, " -Q: defer time (ms)\n");
137 astrand 333 #endif
138 astrand 111 fprintf(stderr, " -u: user name\n");
139     fprintf(stderr, " -d: domain\n");
140     fprintf(stderr, " -s: shell\n");
141     fprintf(stderr, " -c: working directory\n");
142 matthewc 211 fprintf(stderr, " -p: password (- to prompt)\n");
143 astrand 111 fprintf(stderr, " -n: client hostname\n");
144 matthewc 520 fprintf(stderr, " -k: keyboard layout on server (en-us, de, sv, etc.)\n");
145 astrand 111 fprintf(stderr, " -g: desktop geometry (WxH)\n");
146     fprintf(stderr, " -f: full-screen mode\n");
147     fprintf(stderr, " -b: force bitmap updates\n");
148 stargo 855 #ifdef HAVE_ICONV
149     fprintf(stderr, " -L: local codepage\n");
150     #endif
151 astrand 1199 fprintf(stderr, " -A: enable SeamlessRDP mode\n");
152 stargo 609 fprintf(stderr, " -B: use BackingStore of X-server (if available)\n");
153 astrand 111 fprintf(stderr, " -e: disable encryption (French TS)\n");
154 forsberg 471 fprintf(stderr, " -E: disable encryption from client to server\n");
155 astrand 111 fprintf(stderr, " -m: do not send motion events\n");
156 n-ki 279 fprintf(stderr, " -C: use private colour map\n");
157 matthewc 520 fprintf(stderr, " -D: hide window manager decorations\n");
158 astrand 111 fprintf(stderr, " -K: keep window manager key bindings\n");
159 matthewc 520 fprintf(stderr, " -S: caption button size (single application mode)\n");
160 matthewc 223 fprintf(stderr, " -T: window title\n");
161 n-ki 569 fprintf(stderr, " -N: enable numlock syncronization\n");
162 stargo 636 fprintf(stderr, " -X: embed into another window with a given id.\n");
163 matthewc 520 fprintf(stderr, " -a: connection colour depth\n");
164 jsorg71 773 fprintf(stderr, " -z: enable rdp compression\n");
165 jsorg71 725 fprintf(stderr, " -x: RDP5 experience (m[odem 28.8], b[roadband], l[an] or hex nr.)\n");
166     fprintf(stderr, " -P: use persistent bitmap caching\n");
167 n-ki 569 fprintf(stderr, " -r: enable specified device redirection (this flag can be repeated)\n");
168 astrand 608 fprintf(stderr,
169     " '-r comport:COM1=/dev/ttyS0': enable serial redirection of /dev/ttyS0 to COM1\n");
170 n-ki 578 fprintf(stderr, " or COM1=/dev/ttyS0,COM2=/dev/ttyS1\n");
171 astrand 608 fprintf(stderr,
172 astrand 747 " '-r disk:floppy=/mnt/floppy': enable redirection of /mnt/floppy to 'floppy' share\n");
173     fprintf(stderr, " or 'floppy=/mnt/floppy,cdrom=/mnt/cdrom'\n");
174 forsberg 646 fprintf(stderr, " '-r clientname=<client name>': Set the client name displayed\n");
175     fprintf(stderr, " for redirected disks\n");
176 astrand 608 fprintf(stderr,
177     " '-r lptport:LPT1=/dev/lp0': enable parallel redirection of /dev/lp0 to LPT1\n");
178 n-ki 578 fprintf(stderr, " or LPT1=/dev/lp0,LPT2=/dev/lp1\n");
179 n-ki 569 fprintf(stderr, " '-r printer:mydeskjet': enable printer redirection\n");
180 astrand 608 fprintf(stderr,
181 n-ki 628 " or mydeskjet=\"HP LaserJet IIIP\" to enter server driver as well\n");
182 stargo 1255 #ifdef WITH_RDPSND
183     fprintf(stderr,
184     " '-r sound:[local[:driver[:device]]|off|remote]': enable sound redirection\n");
185 n-ki 628 fprintf(stderr, " remote would leave sound on server\n");
186 stargo 1255 fprintf(stderr, " available drivers for 'local':\n");
187     rdpsnd_show_help();
188     #endif
189 ossman_ 1207 fprintf(stderr,
190 ossman_ 1215 " '-r clipboard:[off|PRIMARYCLIPBOARD|CLIPBOARD]': enable clipboard\n");
191     fprintf(stderr, " redirection.\n");
192 ossman_ 1207 fprintf(stderr,
193 ossman_ 1215 " 'PRIMARYCLIPBOARD' looks at both PRIMARY and CLIPBOARD\n");
194     fprintf(stderr, " when sending data to server.\n");
195 ossman_ 1207 fprintf(stderr, " 'CLIPBOARD' looks at only CLIPBOARD.\n");
196 matthewc 482 fprintf(stderr, " -0: attach to console\n");
197     fprintf(stderr, " -4: use RDP version 4\n");
198     fprintf(stderr, " -5: use RDP version 5 (default)\n");
199 matty 10 }
200    
201 astrand 944 static void
202 astrand 676 print_disconnect_reason(uint16 reason)
203     {
204     char *text;
205    
206     switch (reason)
207     {
208     case exDiscReasonNoInfo:
209     text = "No information available";
210     break;
211    
212     case exDiscReasonAPIInitiatedDisconnect:
213     text = "Server initiated disconnect";
214     break;
215    
216     case exDiscReasonAPIInitiatedLogoff:
217     text = "Server initiated logoff";
218     break;
219    
220     case exDiscReasonServerIdleTimeout:
221     text = "Server idle timeout reached";
222     break;
223    
224     case exDiscReasonServerLogonTimeout:
225     text = "Server logon timeout reached";
226     break;
227    
228     case exDiscReasonReplacedByOtherConnection:
229     text = "The session was replaced";
230     break;
231    
232     case exDiscReasonOutOfMemory:
233     text = "The server is out of memory";
234     break;
235    
236     case exDiscReasonServerDeniedConnection:
237     text = "The server denied the connection";
238     break;
239    
240     case exDiscReasonServerDeniedConnectionFips:
241     text = "The server denied the connection for security reason";
242     break;
243    
244     case exDiscReasonLicenseInternal:
245     text = "Internal licensing error";
246     break;
247    
248     case exDiscReasonLicenseNoLicenseServer:
249     text = "No license server available";
250     break;
251    
252     case exDiscReasonLicenseNoLicense:
253     text = "No valid license available";
254     break;
255    
256     case exDiscReasonLicenseErrClientMsg:
257     text = "Invalid licensing message";
258     break;
259    
260     case exDiscReasonLicenseHwidDoesntMatchLicense:
261     text = "Hardware id doesn't match software license";
262     break;
263    
264     case exDiscReasonLicenseErrClientLicense:
265     text = "Client license error";
266     break;
267    
268     case exDiscReasonLicenseCantFinishProtocol:
269     text = "Network error during licensing protocol";
270     break;
271    
272     case exDiscReasonLicenseClientEndedProtocol:
273     text = "Licensing protocol was not completed";
274     break;
275    
276     case exDiscReasonLicenseErrClientEncryption:
277     text = "Incorrect client license enryption";
278     break;
279    
280     case exDiscReasonLicenseCantUpgradeLicense:
281     text = "Can't upgrade license";
282     break;
283    
284     case exDiscReasonLicenseNoRemoteConnections:
285     text = "The server is not licensed to accept remote connections";
286     break;
287    
288     default:
289     if (reason > 0x1000 && reason < 0x7fff)
290     {
291     text = "Internal protocol error";
292     }
293     else
294     {
295     text = "Unknown reason";
296     }
297     }
298     fprintf(stderr, "disconnect: %s.\n", text);
299     }
300    
301 astrand 977 static void
302     rdesktop_reset_state(void)
303     {
304     rdp_reset_state();
305     }
306    
307 matthewc 211 static BOOL
308     read_password(char *password, int size)
309     {
310     struct termios tios;
311     BOOL ret = False;
312     int istty = 0;
313     char *p;
314    
315     if (tcgetattr(STDIN_FILENO, &tios) == 0)
316     {
317     fprintf(stderr, "Password: ");
318     tios.c_lflag &= ~ECHO;
319     tcsetattr(STDIN_FILENO, TCSANOW, &tios);
320     istty = 1;
321     }
322    
323     if (fgets(password, size, stdin) != NULL)
324     {
325     ret = True;
326    
327     /* strip final newline */
328     p = strchr(password, '\n');
329     if (p != NULL)
330     *p = 0;
331     }
332    
333     if (istty)
334     {
335     tios.c_lflag |= ECHO;
336     tcsetattr(STDIN_FILENO, TCSANOW, &tios);
337     fprintf(stderr, "\n");
338     }
339    
340     return ret;
341     }
342    
343 astrand 444 static void
344     parse_server_and_port(char *server)
345     {
346     char *p;
347     #ifdef IPv6
348     int addr_colons;
349     #endif
350    
351     #ifdef IPv6
352     p = server;
353     addr_colons = 0;
354     while (*p)
355     if (*p++ == ':')
356     addr_colons++;
357     if (addr_colons >= 2)
358     {
359     /* numeric IPv6 style address format - [1:2:3::4]:port */
360     p = strchr(server, ']');
361     if (*server == '[' && p != NULL)
362     {
363     if (*(p + 1) == ':' && *(p + 2) != '\0')
364 jsorg71 710 g_tcp_port_rdp = strtol(p + 2, NULL, 10);
365 astrand 444 /* remove the port number and brackets from the address */
366     *p = '\0';
367     strncpy(server, server + 1, strlen(server));
368     }
369     }
370     else
371     {
372     /* dns name or IPv4 style address format - server.example.com:port or 1.2.3.4:port */
373     p = strchr(server, ':');
374     if (p != NULL)
375     {
376 jsorg71 710 g_tcp_port_rdp = strtol(p + 1, NULL, 10);
377 astrand 444 *p = 0;
378     }
379     }
380     #else /* no IPv6 support */
381     p = strchr(server, ':');
382     if (p != NULL)
383     {
384 jsorg71 710 g_tcp_port_rdp = strtol(p + 1, NULL, 10);
385 astrand 444 *p = 0;
386     }
387     #endif /* IPv6 */
388    
389     }
390    
391 matty 10 /* Client program */
392 matty 25 int
393     main(int argc, char *argv[])
394 matty 10 {
395 matthewc 222 char server[64];
396 matty 30 char fullhostname[64];
397 matty 21 char domain[16];
398 astrand 479 char password[64];
399 forsberg 1046 char shell[256];
400 astrand 1047 char directory[256];
401 astrand 676 BOOL prompt_password, deactivated;
402 matty 30 struct passwd *pw;
403 astrand 676 uint32 flags, ext_disc_reason = 0;
404 matthewc 222 char *p;
405 matty 10 int c;
406 astrand 973 char *locale = NULL;
407 astrand 289 int username_option = 0;
408 astrand 1199 BOOL geometry_option = False;
409 astrand 977 int run_count = 0; /* Session Directory support */
410     BOOL continue_connect = True; /* Session Directory support */
411 matty 10
412 astrand 973 #ifdef HAVE_LOCALE_H
413 astrand 962 /* Set locale according to environment */
414     locale = setlocale(LC_ALL, "");
415     if (locale)
416     {
417 astrand 974 locale = xstrdup(locale);
418 astrand 962 }
419    
420 astrand 973 #endif
421 matty 21 flags = RDP_LOGON_NORMAL;
422 matthewc 211 prompt_password = False;
423 matty 21 domain[0] = password[0] = shell[0] = directory[0] = 0;
424 stargo 636 g_embed_wnd = 0;
425 matty 21
426 n-ki 569 g_num_devices = 0;
427    
428 astrand 333 #ifdef RDP2VNC
429 forsberg 471 #define VNCOPT "V:Q:"
430 astrand 333 #else
431     #define VNCOPT
432     #endif
433    
434 jsorg71 725 while ((c = getopt(argc, argv,
435 astrand 1199 VNCOPT "Au:L:d:s:c:p:n:k:g:fbBeEmzCDKS:T:NX:a:x:Pr:045h?")) != -1)
436 matty 10 {
437     switch (c)
438     {
439 astrand 333 #ifdef RDP2VNC
440     case 'V':
441     rfb_port = strtol(optarg, NULL, 10);
442     if (rfb_port < 100)
443     rfb_port += 5900;
444     break;
445    
446 forsberg 471 case 'Q':
447 astrand 333 defer_time = strtol(optarg, NULL, 10);
448     if (defer_time < 0)
449     defer_time = 0;
450     break;
451     #endif
452    
453 astrand 1199 case 'A':
454     g_seamless_rdp = True;
455     break;
456    
457 matty 10 case 'u':
458 jsorg71 437 STRNCPY(g_username, optarg, sizeof(g_username));
459 astrand 289 username_option = 1;
460 matty 10 break;
461    
462 stargo 855 case 'L':
463     #ifdef HAVE_ICONV
464     STRNCPY(g_codepage, optarg, sizeof(g_codepage));
465     #else
466     error("iconv support not available\n");
467     #endif
468     break;
469    
470 matty 21 case 'd':
471 matty 30 STRNCPY(domain, optarg, sizeof(domain));
472 matty 21 break;
473    
474     case 's':
475 matty 30 STRNCPY(shell, optarg, sizeof(shell));
476 matty 21 break;
477    
478     case 'c':
479 matty 30 STRNCPY(directory, optarg, sizeof(directory));
480 matty 21 break;
481    
482 matty 30 case 'p':
483 matthewc 211 if ((optarg[0] == '-') && (optarg[1] == 0))
484     {
485     prompt_password = True;
486     break;
487     }
488    
489 matty 30 STRNCPY(password, optarg, sizeof(password));
490     flags |= RDP_LOGON_AUTO;
491 matthewc 211
492     /* try to overwrite argument so it won't appear in ps */
493 n-ki 171 p = optarg;
494     while (*p)
495     *(p++) = 'X';
496 matty 30 break;
497    
498 matty 10 case 'n':
499 jsorg71 710 STRNCPY(g_hostname, optarg, sizeof(g_hostname));
500 matty 10 break;
501    
502     case 'k':
503 astrand 975 STRNCPY(g_keymapname, optarg, sizeof(g_keymapname));
504 matty 10 break;
505    
506 matty 30 case 'g':
507 astrand 1199 geometry_option = True;
508 astrand 547 g_fullscreen = False;
509 astrand 263 if (!strcmp(optarg, "workarea"))
510     {
511 jsorg71 447 g_width = g_height = 0;
512 astrand 263 break;
513     }
514    
515 jsorg71 447 g_width = strtol(optarg, &p, 10);
516 astrand 500 if (g_width <= 0)
517     {
518     error("invalid geometry\n");
519     return 1;
520     }
521    
522 matty 30 if (*p == 'x')
523 stargo 800 g_height = strtol(p + 1, &p, 10);
524 matty 30
525 astrand 500 if (g_height <= 0)
526 matty 30 {
527     error("invalid geometry\n");
528     return 1;
529     }
530 astrand 500
531     if (*p == '%')
532 stargo 800 {
533 astrand 500 g_width = -g_width;
534 stargo 800 p++;
535     }
536 astrand 500
537 stargo 800 if (*p == '+' || *p == '-')
538 stargo 867 {
539     g_pos |= (*p == '-') ? 2 : 1;
540 stargo 800 g_xpos = strtol(p, &p, 10);
541 astrand 801
542 stargo 867 }
543 stargo 800 if (*p == '+' || *p == '-')
544 stargo 867 {
545     g_pos |= (*p == '-') ? 4 : 1;
546 stargo 800 g_ypos = strtol(p, NULL, 10);
547 stargo 867 }
548 stargo 800
549 matty 10 break;
550    
551 matty 30 case 'f':
552 jsorg71 447 g_fullscreen = True;
553 matty 30 break;
554    
555 matty 10 case 'b':
556 jsorg71 678 g_bitmap_cache = False;
557 matty 10 break;
558    
559 stargo 609 case 'B':
560     g_ownbackstore = False;
561     break;
562    
563 matty 30 case 'e':
564 jsorg71 437 g_encryption = False;
565 matty 10 break;
566 astrand 435 case 'E':
567 forsberg 427 packet_encryption = False;
568     break;
569 matty 30 case 'm':
570 jsorg71 447 g_sendmotion = False;
571 matty 28 break;
572 matty 29
573 n-ki 279 case 'C':
574 jsorg71 450 g_owncolmap = True;
575 n-ki 279 break;
576    
577 matthewc 520 case 'D':
578     g_hide_decorations = True;
579     break;
580    
581 astrand 76 case 'K':
582 jsorg71 450 g_grab_keyboard = False;
583 astrand 76 break;
584    
585 matthewc 520 case 'S':
586     if (!strcmp(optarg, "standard"))
587     {
588     g_win_button_size = 18;
589     break;
590     }
591    
592     g_win_button_size = strtol(optarg, &p, 10);
593    
594     if (*p)
595     {
596     error("invalid button size\n");
597     return 1;
598     }
599    
600     break;
601    
602 matthewc 223 case 'T':
603 jsorg71 450 STRNCPY(g_title, optarg, sizeof(g_title));
604 astrand 107 break;
605    
606 astrand 552 case 'N':
607     g_numlock_sync = True;
608     break;
609    
610 stargo 636 case 'X':
611 stargo 871 g_embed_wnd = strtol(optarg, NULL, 0);
612 stargo 636 break;
613 astrand 651
614 jsorg71 309 case 'a':
615 astrand 1042 g_server_depth = strtol(optarg, NULL, 10);
616     if (g_server_depth != 8 &&
617     g_server_depth != 16 &&
618     g_server_depth != 15 && g_server_depth != 24)
619 jsorg71 309 {
620 astrand 1042 error("Invalid server colour depth.\n");
621 jsorg71 309 return 1;
622     }
623     break;
624    
625 jsorg71 773 case 'z':
626     DEBUG(("rdp compression enabled\n"));
627 jdmeijer 889 flags |= (RDP_LOGON_COMPRESSION | RDP_LOGON_COMPRESSION2);
628 jsorg71 773 break;
629    
630 stargo 637 case 'x':
631 astrand 1010 if (str_startswith(optarg, "m")) /* modem */
632 stargo 637 {
633 astrand 651 g_rdp5_performanceflags =
634     RDP5_NO_WALLPAPER | RDP5_NO_FULLWINDOWDRAG |
635     RDP5_NO_MENUANIMATIONS | RDP5_NO_THEMING;
636 stargo 637 }
637 astrand 1010 else if (str_startswith(optarg, "b")) /* broadband */
638 stargo 637 {
639     g_rdp5_performanceflags = RDP5_NO_WALLPAPER;
640     }
641 astrand 1010 else if (str_startswith(optarg, "l")) /* lan */
642 stargo 637 {
643     g_rdp5_performanceflags = RDP5_DISABLE_NOTHING;
644     }
645     else
646     {
647     g_rdp5_performanceflags = strtol(optarg, NULL, 16);
648     }
649     break;
650 astrand 651
651 jsorg71 725 case 'P':
652     g_bitmap_cache_persist_enable = True;
653     break;
654    
655 matthewc 520 case 'r':
656 n-ki 569
657 astrand 1010 if (str_startswith(optarg, "sound"))
658 n-ki 569 {
659 n-ki 629 optarg += 5;
660    
661     if (*optarg == ':')
662 n-ki 628 {
663 astrand 1224 optarg++;
664 n-ki 629 while ((p = next_arg(optarg, ',')))
665     {
666 astrand 1010 if (str_startswith(optarg, "remote"))
667 n-ki 629 flags |= RDP_LOGON_LEAVE_AUDIO;
668 n-ki 628
669 astrand 1010 if (str_startswith(optarg, "local"))
670 stargo 501 #ifdef WITH_RDPSND
671 stargo 1255 {
672     char *driver = NULL, *options =
673     NULL;
674    
675     if ((driver =
676     next_arg(optarg, ':')))
677     {
678     if (!strlen(driver))
679     {
680     driver = NULL;
681     }
682     else if ((options =
683     next_arg(driver,
684     ':')))
685     {
686     if (!strlen
687     (options))
688     options =
689     NULL;
690     }
691     }
692    
693 n-ki 629 g_rdpsnd = True;
694 stargo 1255 if (!rdpsnd_select_driver
695     (driver, options))
696     {
697     warning("Driver not available\n");
698     }
699     }
700    
701 matthewc 520 #else
702 stargo 739 warning("Not compiled with sound support\n");
703 matthewc 520 #endif
704 n-ki 629
705 astrand 1010 if (str_startswith(optarg, "off"))
706 stargo 685 #ifdef WITH_RDPSND
707 n-ki 629 g_rdpsnd = False;
708 stargo 685 #else
709 stargo 739 warning("Not compiled with sound support\n");
710 stargo 685 #endif
711 n-ki 629
712     optarg = p;
713 n-ki 628 }
714     }
715     else
716     {
717     #ifdef WITH_RDPSND
718     g_rdpsnd = True;
719 stargo 1255 if (!rdpsnd_select_driver(NULL, NULL))
720     {
721     warning("No sound-driver available\n");
722     }
723 n-ki 628 #else
724 stargo 739 warning("Not compiled with sound support\n");
725 n-ki 628 #endif
726     }
727 n-ki 569 }
728 astrand 1010 else if (str_startswith(optarg, "disk"))
729 n-ki 569 {
730     /* -r disk:h:=/mnt/floppy */
731     disk_enum_devices(&g_num_devices, optarg + 4);
732     }
733 astrand 1010 else if (str_startswith(optarg, "comport"))
734 n-ki 569 {
735     serial_enum_devices(&g_num_devices, optarg + 7);
736     }
737 astrand 1053 else if (str_startswith(optarg, "lspci"))
738     {
739     lspci_enabled = True;
740     }
741 astrand 1010 else if (str_startswith(optarg, "lptport"))
742 n-ki 569 {
743     parallel_enum_devices(&g_num_devices, optarg + 7);
744     }
745 astrand 1010 else if (str_startswith(optarg, "printer"))
746 n-ki 569 {
747     printer_enum_devices(&g_num_devices, optarg + 7);
748     }
749 astrand 1010 else if (str_startswith(optarg, "clientname"))
750 forsberg 646 {
751 astrand 651 g_rdpdr_clientname = xmalloc(strlen(optarg + 11) + 1);
752 forsberg 646 strcpy(g_rdpdr_clientname, optarg + 11);
753     }
754 ossman_ 1207 else if (str_startswith(optarg, "clipboard"))
755     {
756     optarg += 9;
757    
758     if (*optarg == ':')
759     {
760     optarg++;
761    
762     if (str_startswith(optarg, "off"))
763     g_rdpclip = False;
764     else
765     cliprdr_set_mode(optarg);
766     }
767     else
768     g_rdpclip = True;
769     }
770 n-ki 569 else
771     {
772 ossman_ 1207 warning("Unknown -r argument\n\n\tPossible arguments are: comport, disk, lptport, printer, sound, clipboard\n");
773 n-ki 569 }
774 stargo 501 break;
775 matthewc 520
776 matthewc 482 case '0':
777     g_console_session = True;
778     break;
779    
780 astrand 458 case '4':
781     g_use_rdp5 = False;
782     break;
783    
784 forsberg 350 case '5':
785 jsorg71 438 g_use_rdp5 = True;
786 forsberg 350 break;
787 astrand 458
788 matty 28 case 'h':
789 matty 10 case '?':
790     default:
791     usage(argv[0]);
792     return 1;
793     }
794     }
795    
796 stargo 610 if (argc - optind != 1)
797 matty 10 {
798     usage(argv[0]);
799     return 1;
800     }
801    
802 matthewc 222 STRNCPY(server, argv[optind], sizeof(server));
803 astrand 444 parse_server_and_port(server);
804 matty 10
805 astrand 1199 if (g_seamless_rdp)
806     {
807     if (g_win_button_size)
808     {
809     error("You cannot use -S and -A at the same time\n");
810     return 1;
811     }
812     g_rdp5_performanceflags &= ~RDP5_NO_FULLWINDOWDRAG;
813     if (geometry_option)
814     {
815     error("You cannot use -g and -A at the same time\n");
816     return 1;
817     }
818     if (g_fullscreen)
819     {
820     error("You cannot use -f and -A at the same time\n");
821     return 1;
822     }
823     if (g_hide_decorations)
824     {
825     error("You cannot use -D and -A at the same time\n");
826     return 1;
827     }
828     if (g_embed_wnd)
829     {
830     error("You cannot use -X and -A at the same time\n");
831     return 1;
832     }
833     if (!g_use_rdp5)
834     {
835     error("You cannot use -4 and -A at the same time\n");
836     return 1;
837     }
838     g_width = -100;
839     g_grab_keyboard = False;
840     }
841    
842 astrand 289 if (!username_option)
843 matty 10 {
844     pw = getpwuid(getuid());
845     if ((pw == NULL) || (pw->pw_name == NULL))
846     {
847 matty 30 error("could not determine username, use -u\n");
848 matty 10 return 1;
849     }
850    
851 jsorg71 437 STRNCPY(g_username, pw->pw_name, sizeof(g_username));
852 matty 10 }
853    
854 stargo 855 #ifdef HAVE_ICONV
855     if (g_codepage[0] == 0)
856     {
857     if (setlocale(LC_CTYPE, ""))
858     {
859     STRNCPY(g_codepage, nl_langinfo(CODESET), sizeof(g_codepage));
860     }
861     else
862     {
863     STRNCPY(g_codepage, DEFAULT_CODEPAGE, sizeof(g_codepage));
864     }
865     }
866     #endif
867 stargo 861
868 jsorg71 710 if (g_hostname[0] == 0)
869 matty 10 {
870 matty 30 if (gethostname(fullhostname, sizeof(fullhostname)) == -1)
871 matty 10 {
872 matty 30 error("could not determine local hostname, use -n\n");
873 matty 10 return 1;
874     }
875 matty 30
876     p = strchr(fullhostname, '.');
877     if (p != NULL)
878     *p = 0;
879    
880 jsorg71 710 STRNCPY(g_hostname, fullhostname, sizeof(g_hostname));
881 matty 10 }
882    
883 astrand 975 if (g_keymapname[0] == 0)
884 astrand 973 {
885     if (locale && xkeymap_from_locale(locale))
886     {
887 astrand 975 fprintf(stderr, "Autoselected keyboard map %s\n", g_keymapname);
888 astrand 973 }
889     else
890     {
891 astrand 975 STRNCPY(g_keymapname, "en-us", sizeof(g_keymapname));
892 astrand 973 }
893     }
894     if (locale)
895     xfree(locale);
896    
897    
898 matthewc 211 if (prompt_password && read_password(password, sizeof(password)))
899     flags |= RDP_LOGON_AUTO;
900 matty 30
901 jsorg71 450 if (g_title[0] == 0)
902 astrand 107 {
903 jsorg71 450 strcpy(g_title, "rdesktop - ");
904     strncat(g_title, server, sizeof(g_title) - sizeof("rdesktop - "));
905 astrand 107 }
906 matty 12
907 astrand 333 #ifdef RDP2VNC
908     rdp2vnc_connect(server, flags, domain, password, shell, directory);
909 forsberg 424 return 0;
910 astrand 333 #else
911    
912 astrand 82 if (!ui_init())
913     return 1;
914 astrand 66
915 matthewc 474 #ifdef WITH_RDPSND
916 stargo 501 if (g_rdpsnd)
917     rdpsnd_init();
918 matthewc 474 #endif
919 astrand 1053
920     if (lspci_enabled)
921     lspci_init();
922    
923 n-ki 569 rdpdr_init();
924 forsberg 416
925 astrand 977 while (run_count < 2 && continue_connect) /* add support for Session Directory; only reconnect once */
926     {
927     if (run_count == 0)
928     {
929     if (!rdp_connect(server, flags, domain, password, shell, directory))
930     return 1;
931     }
932     else if (!rdp_reconnect
933     (server, flags, domain, password, shell, directory, g_redirect_cookie))
934     return 1;
935 matthewc 53
936 astrand 977 /* By setting encryption to False here, we have an encrypted login
937     packet but unencrypted transfer of other packets */
938     if (!packet_encryption)
939     g_encryption = False;
940 forsberg 427
941    
942 astrand 977 DEBUG(("Connection successful.\n"));
943     memset(password, 0, sizeof(password));
944 matthewc 53
945 astrand 977 if (run_count == 0)
946     if (!ui_create_window())
947     continue_connect = False;
948    
949     if (continue_connect)
950     rdp_main_loop(&deactivated, &ext_disc_reason);
951    
952     DEBUG(("Disconnecting...\n"));
953     rdp_disconnect();
954    
955     if ((g_redirect == True) && (run_count == 0)) /* Support for Session Directory */
956     {
957     /* reset state of major globals */
958     rdesktop_reset_state();
959    
960     STRNCPY(domain, g_redirect_domain, sizeof(domain));
961     STRNCPY(g_username, g_redirect_username, sizeof(g_username));
962     STRNCPY(password, g_redirect_password, sizeof(password));
963     STRNCPY(server, g_redirect_server, sizeof(server));
964     flags |= RDP_LOGON_AUTO;
965    
966     g_redirect = False;
967     }
968     else
969     {
970     continue_connect = False;
971     ui_destroy_window();
972     break;
973     }
974    
975     run_count++;
976 matty 10 }
977    
978 jsorg71 725 cache_save_state();
979 matthewc 188 ui_deinit();
980 astrand 333
981 astrand 676 if (ext_disc_reason >= 2)
982     print_disconnect_reason(ext_disc_reason);
983    
984     if (deactivated)
985     {
986     /* clean disconnect */
987 forsberg 424 return 0;
988 astrand 676 }
989 forsberg 424 else
990 astrand 676 {
991     if (ext_disc_reason == exDiscReasonAPIInitiatedDisconnect
992     || ext_disc_reason == exDiscReasonAPIInitiatedLogoff)
993     {
994     /* not so clean disconnect, but nothing to worry about */
995     return 0;
996     }
997     else
998     {
999     /* return error */
1000     return 2;
1001     }
1002     }
1003 forsberg 424
1004 astrand 333 #endif
1005    
1006 matty 10 }
1007    
1008 matthewc 220 #ifdef EGD_SOCKET
1009     /* Read 32 random bytes from PRNGD or EGD socket (based on OpenSSL RAND_egd) */
1010     static BOOL
1011     generate_random_egd(uint8 * buf)
1012     {
1013     struct sockaddr_un addr;
1014     BOOL ret = False;
1015     int fd;
1016    
1017     fd = socket(AF_UNIX, SOCK_STREAM, 0);
1018     if (fd == -1)
1019     return False;
1020    
1021     addr.sun_family = AF_UNIX;
1022     memcpy(addr.sun_path, EGD_SOCKET, sizeof(EGD_SOCKET));
1023 astrand 259 if (connect(fd, (struct sockaddr *) &addr, sizeof(addr)) == -1)
1024 matthewc 220 goto err;
1025    
1026     /* PRNGD and EGD use a simple communications protocol */
1027 astrand 259 buf[0] = 1; /* Non-blocking (similar to /dev/urandom) */
1028     buf[1] = 32; /* Number of requested random bytes */
1029 matthewc 220 if (write(fd, buf, 2) != 2)
1030     goto err;
1031    
1032 astrand 259 if ((read(fd, buf, 1) != 1) || (buf[0] == 0)) /* Available? */
1033 matthewc 220 goto err;
1034    
1035     if (read(fd, buf, 32) != 32)
1036     goto err;
1037    
1038     ret = True;
1039    
1040 astrand 259 err:
1041 matthewc 220 close(fd);
1042     return ret;
1043     }
1044     #endif
1045    
1046 matty 10 /* Generate a 32-byte random for the secure transport code. */
1047 matty 25 void
1048 astrand 64 generate_random(uint8 * random)
1049 matty 10 {
1050     struct stat st;
1051 matty 22 struct tms tmsbuf;
1052 matthewc 220 MD5_CTX md5;
1053     uint32 *r;
1054     int fd, n;
1055 matty 10
1056 matthewc 220 /* If we have a kernel random device, try that first */
1057 matty 30 if (((fd = open("/dev/urandom", O_RDONLY)) != -1)
1058     || ((fd = open("/dev/random", O_RDONLY)) != -1))
1059 matty 10 {
1060 matthewc 220 n = read(fd, random, 32);
1061 matty 10 close(fd);
1062 matthewc 220 if (n == 32)
1063     return;
1064 matty 10 }
1065    
1066 matthewc 220 #ifdef EGD_SOCKET
1067     /* As a second preference use an EGD */
1068     if (generate_random_egd(random))
1069     return;
1070     #endif
1071    
1072 matty 10 /* Otherwise use whatever entropy we can gather - ideas welcome. */
1073 astrand 259 r = (uint32 *) random;
1074 matty 10 r[0] = (getpid()) | (getppid() << 16);
1075     r[1] = (getuid()) | (getgid() << 16);
1076 matty 24 r[2] = times(&tmsbuf); /* system uptime (clocks) */
1077     gettimeofday((struct timeval *) &r[3], NULL); /* sec and usec */
1078 matty 10 stat("/tmp", &st);
1079     r[5] = st.st_atime;
1080     r[6] = st.st_mtime;
1081     r[7] = st.st_ctime;
1082 matthewc 220
1083     /* Hash both halves with MD5 to obscure possible patterns */
1084     MD5_Init(&md5);
1085 astrand 259 MD5_Update(&md5, random, 16);
1086 matthewc 220 MD5_Final(random, &md5);
1087 astrand 259 MD5_Update(&md5, random + 16, 16);
1088     MD5_Final(random + 16, &md5);
1089 matty 10 }
1090    
1091     /* malloc; exit if out of memory */
1092 matty 25 void *
1093     xmalloc(int size)
1094 matty 10 {
1095     void *mem = malloc(size);
1096     if (mem == NULL)
1097     {
1098 matty 30 error("xmalloc %d\n", size);
1099 matty 10 exit(1);
1100     }
1101     return mem;
1102     }
1103    
1104 astrand 974 /* strdup */
1105     char *
1106     xstrdup(const char *s)
1107     {
1108     char *mem = strdup(s);
1109     if (mem == NULL)
1110     {
1111     perror("strdup");
1112     exit(1);
1113     }
1114     return mem;
1115     }
1116    
1117 matty 10 /* realloc; exit if out of memory */
1118 matty 25 void *
1119     xrealloc(void *oldmem, int size)
1120 matty 10 {
1121 astrand 782 void *mem;
1122 jsorg71 773
1123     if (size < 1)
1124     size = 1;
1125     mem = realloc(oldmem, size);
1126 matty 10 if (mem == NULL)
1127     {
1128 matty 30 error("xrealloc %d\n", size);
1129 matty 10 exit(1);
1130     }
1131     return mem;
1132     }
1133    
1134     /* free */
1135 matty 25 void
1136     xfree(void *mem)
1137 matty 10 {
1138     free(mem);
1139     }
1140    
1141 matty 30 /* report an error */
1142 matty 25 void
1143 matty 30 error(char *format, ...)
1144     {
1145     va_list ap;
1146    
1147     fprintf(stderr, "ERROR: ");
1148    
1149     va_start(ap, format);
1150     vfprintf(stderr, format, ap);
1151     va_end(ap);
1152     }
1153    
1154 matthewc 297 /* report a warning */
1155     void
1156     warning(char *format, ...)
1157     {
1158     va_list ap;
1159    
1160     fprintf(stderr, "WARNING: ");
1161    
1162     va_start(ap, format);
1163     vfprintf(stderr, format, ap);
1164     va_end(ap);
1165     }
1166    
1167 matty 30 /* report an unimplemented protocol feature */
1168     void
1169     unimpl(char *format, ...)
1170     {
1171     va_list ap;
1172    
1173     fprintf(stderr, "NOT IMPLEMENTED: ");
1174    
1175     va_start(ap, format);
1176     vfprintf(stderr, format, ap);
1177     va_end(ap);
1178     }
1179    
1180     /* produce a hex dump */
1181     void
1182 n-ki 569 hexdump(unsigned char *p, unsigned int len)
1183 matty 10 {
1184     unsigned char *line = p;
1185 jsorg71 376 int i, thisline, offset = 0;
1186 matty 10
1187     while (offset < len)
1188     {
1189 matthewc 169 printf("%04x ", offset);
1190 matty 10 thisline = len - offset;
1191     if (thisline > 16)
1192     thisline = 16;
1193    
1194     for (i = 0; i < thisline; i++)
1195 matthewc 169 printf("%02x ", line[i]);
1196 matty 10
1197 matty 30 for (; i < 16; i++)
1198 matthewc 169 printf(" ");
1199 matty 30
1200 matty 10 for (i = 0; i < thisline; i++)
1201 matthewc 169 printf("%c", (line[i] >= 0x20 && line[i] < 0x7f) ? line[i] : '.');
1202 matty 10
1203 matthewc 169 printf("\n");
1204 matty 10 offset += thisline;
1205     line += thisline;
1206     }
1207     }
1208 astrand 325
1209 n-ki 569 /*
1210 n-ki 583 input: src is the string we look in for needle.
1211     Needle may be escaped by a backslash, in
1212     that case we ignore that particular needle.
1213 n-ki 569 return value: returns next src pointer, for
1214     succesive executions, like in a while loop
1215     if retval is 0, then there are no more args.
1216     pitfalls:
1217     src is modified. 0x00 chars are inserted to
1218     terminate strings.
1219     return val, points on the next val chr after ins
1220     0x00
1221 astrand 325
1222 n-ki 569 example usage:
1223     while( (pos = next_arg( optarg, ',')) ){
1224     printf("%s\n",optarg);
1225     optarg=pos;
1226     }
1227    
1228     */
1229     char *
1230     next_arg(char *src, char needle)
1231     {
1232     char *nextval;
1233 n-ki 571 char *p;
1234 n-ki 575 char *mvp = 0;
1235 n-ki 569
1236 n-ki 575 /* EOS */
1237 n-ki 569 if (*src == (char) 0x00)
1238     return 0;
1239    
1240 n-ki 571 p = src;
1241 n-ki 575 /* skip escaped needles */
1242 astrand 580 while ((nextval = strchr(p, needle)))
1243 n-ki 571 {
1244 n-ki 575 mvp = nextval - 1;
1245     /* found backslashed needle */
1246 astrand 580 if (*mvp == '\\' && (mvp > src))
1247 n-ki 575 {
1248     /* move string one to the left */
1249 astrand 580 while (*(mvp + 1) != (char) 0x00)
1250 n-ki 575 {
1251 astrand 580 *mvp = *(mvp + 1);
1252 astrand 1224 mvp++;
1253 n-ki 575 }
1254 astrand 580 *mvp = (char) 0x00;
1255 n-ki 575 p = nextval;
1256     }
1257     else
1258     {
1259 astrand 580 p = nextval + 1;
1260 n-ki 571 break;
1261 n-ki 575 }
1262    
1263 n-ki 571 }
1264    
1265 n-ki 575 /* more args available */
1266 n-ki 569 if (nextval)
1267     {
1268     *nextval = (char) 0x00;
1269     return ++nextval;
1270     }
1271    
1272 n-ki 575 /* no more args after this, jump to EOS */
1273 n-ki 569 nextval = src + strlen(src);
1274     return nextval;
1275     }
1276    
1277    
1278 stargo 570 void
1279 astrand 580 toupper_str(char *p)
1280 n-ki 569 {
1281 astrand 580 while (*p)
1282     {
1283     if ((*p >= 'a') && (*p <= 'z'))
1284 stargo 570 *p = toupper((int) *p);
1285 n-ki 569 p++;
1286     }
1287     }
1288    
1289    
1290 astrand 1010 BOOL
1291     str_startswith(const char *s, const char *prefix)
1292     {
1293     return (strncmp(s, prefix, strlen(prefix)) == 0);
1294     }
1295    
1296    
1297 astrand 1053 /* Split input into lines, and call linehandler for each
1298     line. Incomplete lines are saved in the rest variable, which should
1299     initially point to NULL. When linehandler returns False, stop and
1300     return False. Otherwise, return True. */
1301     BOOL
1302     str_handle_lines(const char *input, char **rest, str_handle_lines_t linehandler, void *data)
1303     {
1304     char *buf, *p;
1305     char *oldrest;
1306     size_t inputlen;
1307     size_t buflen;
1308     size_t restlen = 0;
1309     BOOL ret = True;
1310    
1311     /* Copy data to buffer */
1312     inputlen = strlen(input);
1313     if (*rest)
1314     restlen = strlen(*rest);
1315     buflen = restlen + inputlen + 1;
1316     buf = (char *) xmalloc(buflen);
1317     buf[0] = '\0';
1318     if (*rest)
1319     STRNCPY(buf, *rest, buflen);
1320     strncat(buf, input, inputlen);
1321     p = buf;
1322    
1323     while (1)
1324     {
1325     char *newline = strchr(p, '\n');
1326     if (newline)
1327     {
1328     *newline = '\0';
1329     if (!linehandler(p, data))
1330     {
1331     p = newline + 1;
1332     ret = False;
1333     break;
1334     }
1335     p = newline + 1;
1336     }
1337     else
1338     {
1339     break;
1340    
1341     }
1342     }
1343    
1344     /* Save in rest */
1345     oldrest = *rest;
1346     restlen = buf + buflen - p;
1347     *rest = (char *) xmalloc(restlen);
1348     STRNCPY((*rest), p, restlen);
1349     xfree(oldrest);
1350    
1351     xfree(buf);
1352     return ret;
1353     }
1354    
1355     /* Execute the program specified by argv. For each line in
1356     stdout/stderr output, call linehandler. Returns false on failure. */
1357     BOOL
1358     subprocess(char *const argv[], str_handle_lines_t linehandler, void *data)
1359     {
1360     pid_t child;
1361     int fd[2];
1362     int n = 1;
1363     char output[256];
1364     char *rest = NULL;
1365    
1366     if (pipe(fd) < 0)
1367     {
1368     perror("pipe");
1369     return False;
1370     }
1371    
1372     if ((child = fork()) < 0)
1373     {
1374     perror("fork");
1375     return False;
1376     }
1377    
1378     /* Child */
1379     if (child == 0)
1380     {
1381     /* Close read end */
1382     close(fd[0]);
1383    
1384     /* Redirect stdout and stderr to pipe */
1385     dup2(fd[1], 1);
1386     dup2(fd[1], 2);
1387    
1388     /* Execute */
1389     execvp(argv[0], argv);
1390     perror("Error executing child");
1391     _exit(128);
1392     }
1393    
1394     /* Parent. Close write end. */
1395     close(fd[1]);
1396     while (n > 0)
1397     {
1398     n = read(fd[0], output, 255);
1399     output[n] = '\0';
1400     str_handle_lines(output, &rest, linehandler, data);
1401     }
1402     xfree(rest);
1403    
1404     return True;
1405     }
1406    
1407    
1408 n-ki 569 /* not all clibs got ltoa */
1409     #define LTOA_BUFSIZE (sizeof(long) * 8 + 1)
1410    
1411     char *
1412 stargo 603 l_to_a(long N, int base)
1413 n-ki 569 {
1414     static char ret[LTOA_BUFSIZE];
1415    
1416 n-ki 583 char *head = ret, buf[LTOA_BUFSIZE], *tail = buf + sizeof(buf);
1417 n-ki 569
1418 n-ki 583 register int divrem;
1419    
1420     if (base < 36 || 2 > base)
1421 n-ki 569 base = 10;
1422    
1423 n-ki 583 if (N < 0)
1424 n-ki 569 {
1425     *head++ = '-';
1426 n-ki 583 N = -N;
1427 n-ki 569 }
1428    
1429 n-ki 583 tail = buf + sizeof(buf);
1430     *--tail = 0;
1431    
1432     do
1433 n-ki 569 {
1434 n-ki 583 divrem = N % base;
1435     *--tail = (divrem <= 9) ? divrem + '0' : divrem + 'a' - 10;
1436     N /= base;
1437 n-ki 569 }
1438 n-ki 583 while (N);
1439 n-ki 569
1440 n-ki 583 strcpy(head, tail);
1441 n-ki 569 return ret;
1442     }
1443    
1444    
1445 astrand 325 int
1446     load_licence(unsigned char **data)
1447     {
1448 matthewc 367 char *home, *path;
1449 astrand 325 struct stat st;
1450 matthewc 367 int fd, length;
1451 astrand 325
1452     home = getenv("HOME");
1453     if (home == NULL)
1454     return -1;
1455    
1456 jsorg71 710 path = (char *) xmalloc(strlen(home) + strlen(g_hostname) + sizeof("/.rdesktop/licence."));
1457     sprintf(path, "%s/.rdesktop/licence.%s", home, g_hostname);
1458 astrand 325
1459     fd = open(path, O_RDONLY);
1460     if (fd == -1)
1461     return -1;
1462    
1463     if (fstat(fd, &st))
1464     return -1;
1465    
1466 forsberg 416 *data = (uint8 *) xmalloc(st.st_size);
1467 matthewc 367 length = read(fd, *data, st.st_size);
1468     close(fd);
1469     xfree(path);
1470     return length;
1471 astrand 325 }
1472    
1473     void
1474     save_licence(unsigned char *data, int length)
1475     {
1476 matthewc 367 char *home, *path, *tmppath;
1477     int fd;
1478 astrand 325
1479     home = getenv("HOME");
1480     if (home == NULL)
1481     return;
1482    
1483 jsorg71 710 path = (char *) xmalloc(strlen(home) + strlen(g_hostname) + sizeof("/.rdesktop/licence."));
1484 astrand 325
1485 matthewc 367 sprintf(path, "%s/.rdesktop", home);
1486     if ((mkdir(path, 0700) == -1) && errno != EEXIST)
1487 astrand 325 {
1488 matthewc 367 perror(path);
1489     return;
1490 astrand 325 }
1491    
1492 matthewc 367 /* write licence to licence.hostname.new, then atomically rename to licence.hostname */
1493 astrand 325
1494 jsorg71 710 sprintf(path, "%s/.rdesktop/licence.%s", home, g_hostname);
1495 forsberg 416 tmppath = (char *) xmalloc(strlen(path) + sizeof(".new"));
1496 matthewc 367 strcpy(tmppath, path);
1497     strcat(tmppath, ".new");
1498    
1499 forsberg 416 fd = open(tmppath, O_WRONLY | O_CREAT | O_TRUNC, 0600);
1500 matthewc 367 if (fd == -1)
1501 astrand 325 {
1502 matthewc 367 perror(tmppath);
1503     return;
1504 astrand 325 }
1505    
1506 matthewc 367 if (write(fd, data, length) != length)
1507 astrand 325 {
1508 matthewc 367 perror(tmppath);
1509     unlink(tmppath);
1510 astrand 325 }
1511 matthewc 367 else if (rename(tmppath, path) == -1)
1512 astrand 325 {
1513 matthewc 367 perror(path);
1514     unlink(tmppath);
1515 astrand 325 }
1516    
1517 matthewc 367 close(fd);
1518     xfree(tmppath);
1519     xfree(path);
1520 astrand 325 }
1521 jsorg71 725
1522     /* Create the bitmap cache directory */
1523     BOOL
1524     rd_pstcache_mkdir(void)
1525     {
1526     char *home;
1527     char bmpcache_dir[256];
1528    
1529     home = getenv("HOME");
1530    
1531     if (home == NULL)
1532     return False;
1533    
1534     sprintf(bmpcache_dir, "%s/%s", home, ".rdesktop");
1535    
1536     if ((mkdir(bmpcache_dir, S_IRWXU) == -1) && errno != EEXIST)
1537     {
1538     perror(bmpcache_dir);
1539     return False;
1540     }
1541    
1542     sprintf(bmpcache_dir, "%s/%s", home, ".rdesktop/cache");
1543    
1544     if ((mkdir(bmpcache_dir, S_IRWXU) == -1) && errno != EEXIST)
1545     {
1546     perror(bmpcache_dir);
1547     return False;
1548     }
1549    
1550     return True;
1551     }
1552    
1553     /* open a file in the .rdesktop directory */
1554     int
1555     rd_open_file(char *filename)
1556     {
1557     char *home;
1558     char fn[256];
1559 astrand 738 int fd;
1560 jsorg71 725
1561     home = getenv("HOME");
1562     if (home == NULL)
1563     return -1;
1564     sprintf(fn, "%s/.rdesktop/%s", home, filename);
1565     fd = open(fn, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
1566     if (fd == -1)
1567     perror(fn);
1568     return fd;
1569     }
1570    
1571     /* close file */
1572     void
1573     rd_close_file(int fd)
1574     {
1575 astrand 738 close(fd);
1576 jsorg71 725 }
1577    
1578     /* read from file*/
1579     int
1580     rd_read_file(int fd, void *ptr, int len)
1581     {
1582 astrand 738 return read(fd, ptr, len);
1583 jsorg71 725 }
1584    
1585     /* write to file */
1586     int
1587 astrand 738 rd_write_file(int fd, void *ptr, int len)
1588 jsorg71 725 {
1589 astrand 738 return write(fd, ptr, len);
1590 jsorg71 725 }
1591    
1592     /* move file pointer */
1593     int
1594     rd_lseek_file(int fd, int offset)
1595     {
1596 astrand 738 return lseek(fd, offset, SEEK_SET);
1597 jsorg71 725 }
1598    
1599     /* do a write lock on a file */
1600     BOOL
1601     rd_lock_file(int fd, int start, int len)
1602     {
1603     struct flock lock;
1604    
1605     lock.l_type = F_WRLCK;
1606     lock.l_whence = SEEK_SET;
1607     lock.l_start = start;
1608     lock.l_len = len;
1609     if (fcntl(fd, F_SETLK, &lock) == -1)
1610     return False;
1611     return True;
1612     }

  ViewVC Help
Powered by ViewVC 1.1.26