/[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 1508 - (hide annotations)
Mon Jul 20 16:47:49 2009 UTC (14 years, 11 months ago) by dpavlin
File MIME type: text/plain
File size: 35331 byte(s)
Date: Sun, 19 Jul 2009 14:00:30 -0400
From: Daniel Jarboe <daniel.jarboe(at)gmail.com>
To: Dobrica Pavlinusic <dpavlin(at)rot13.org>
Subject: Re: rdesktop diff

On Sun, Jul 19, 2009 at 8:01 AM, Dobrica Pavlinusic <dpavlin(at)rot13.org>wrote:
>
> I'm looking forward for your patch, and will keep you informed what I
> did with it :-)

This diff was an earlier one with some debug printfs in so you can see how
the tuning knobs work.  I was only keeping an eye on a young computer user's
activities so ignored small screen changes and wrote out the stills to lossy
jpegs with libjpeg.  If you plan on saving screens no matter if there are
changes or not then I'd throw away all the g_bitmap_data_last_write stuff.

diff is against rdesktop-1.6 with whatever patches are in ubuntu 9.04
jaunty.  Added libjpeg62-dev in addition to the regular rdesktop build
dependencies.  Have fun and thanks for letting me know what you end up with.

~ Daniel

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

  ViewVC Help
Powered by ViewVC 1.1.26