Added RDP alternate shell / working dir, #3943
Ylian Saint-Hilaire committed
May 8, 2022 at 11:46 UTC
6797f8199c2c6ef2504a71bedd39c662b18d25bc
4 files changed
+243
-228
apprelays.js
+5
-1
@@ -179,7 +179,11 @@ module.exports.CreateMstscRelay = function (parent, db, ws, req, args, domain) {
179
screen: obj.infos.screen,
180
locale: obj.infos.locale,
181
};
182
- if (obj.infos.options && (obj.infos.options.flags != null)) { args.perfFlags = obj.infos.options.flags; delete obj.infos.options.flags; }
182
+ if (obj.infos.options) {
183
+ if (obj.infos.options.flags != null) { args.perfFlags = obj.infos.options.flags; delete obj.infos.options.flags; }
184
+ if ((obj.infos.options.workingDir != null) && (obj.infos.options.workingDir != '')) { args.workingDir = obj.infos.options.workingDir; }
185
+ if ((obj.infos.options.alternateShell != null) && (obj.infos.options.alternateShell != '')) { args.alternateShell = obj.infos.options.alternateShell; }
186
+ }
187
rdpClient = require('./rdp').createClient(args).on('connect', function () {
188
send(['rdp-connect']);
189
if ((typeof obj.infos.options == 'object') && (obj.infos.options.savepass == true)) { saveRdpCredentials(); } // Save the credentials if needed
public/scripts/agent-rdp-0.0.1.js
+1
-1
@@ -27,7 +27,7 @@ var CreateRDPDesktop = function (canvasid) {
27
obj.nodeid = nodeid;
28
obj.port = port;
29
obj.credentials = credentials;
30
- var options = { savepass: credentials.savecred, useServerCreds: credentials.servercred, width: credentials.width, height: credentials.height, flags: credentials.flags };
30
+ var options = { savepass: credentials.savecred, useServerCreds: credentials.servercred, width: credentials.width, height: credentials.height, flags: credentials.flags, workingDir: credentials.workdir, alternateShell: credentials.altshell };
31
if (credentials.width && credentials.height) {
32
options.width = obj.ScreenWidth = obj.width = credentials.width;
33
options.height = obj.ScreenHeight = obj.height = credentials.height;
rdp/protocol/rdp.js
+221
-221
@@ -33,81 +33,81 @@ var pdu = require('./pdu');
33
* decompress bitmap from RLE algorithm
34
* @param bitmap {object} bitmap object of bitmap event of node-rdpjs
35
*/
36
-function decompress (bitmap) {
37
- var fName = null;
38
- switch (bitmap.bitsPerPixel.value) {
39
- case 15:
40
- fName = 'bitmap_decompress_15';
41
- break;
42
- case 16:
43
- fName = 'bitmap_decompress_16';
44
- break;
45
- case 24:
46
- fName = 'bitmap_decompress_24';
47
- break;
48
- case 32:
49
- fName = 'bitmap_decompress_32';
50
- break;
51
- default:
52
- throw 'invalid bitmap data format';
53
- }
54
-
55
- var input = new Uint8Array(bitmap.bitmapDataStream.value);
56
- var inputPtr = rle._malloc(input.length);
57
- var inputHeap = new Uint8Array(rle.HEAPU8.buffer, inputPtr, input.length);
58
- inputHeap.set(input);
59
-
60
- var ouputSize = bitmap.width.value * bitmap.height.value * 4;
61
- var outputPtr = rle._malloc(ouputSize);
62
-
63
- var outputHeap = new Uint8Array(rle.HEAPU8.buffer, outputPtr, ouputSize);
64
-
65
- var res = rle.ccall(fName,
66
- 'number',
67
- ['number', 'number', 'number', 'number', 'number', 'number', 'number', 'number'],
68
- [outputHeap.byteOffset, bitmap.width.value, bitmap.height.value, bitmap.width.value, bitmap.height.value, inputHeap.byteOffset, input.length]
69
- );
70
-
71
- var output = new Uint8ClampedArray(outputHeap.buffer, outputHeap.byteOffset, ouputSize);
72
-
73
- rle._free(inputPtr);
74
- rle._free(outputPtr);
75
-
76
- return output;
36
+function decompress(bitmap) {
37
+ var fName = null;
38
+ switch (bitmap.bitsPerPixel.value) {
39
+ case 15:
40
+ fName = 'bitmap_decompress_15';
41
+ break;
42
+ case 16:
43
+ fName = 'bitmap_decompress_16';
44
+ break;
45
+ case 24:
46
+ fName = 'bitmap_decompress_24';
47
+ break;
48
+ case 32:
49
+ fName = 'bitmap_decompress_32';
50
+ break;
51
+ default:
52
+ throw 'invalid bitmap data format';
53
+ }
54
+
55
+ var input = new Uint8Array(bitmap.bitmapDataStream.value);
56
+ var inputPtr = rle._malloc(input.length);
57
+ var inputHeap = new Uint8Array(rle.HEAPU8.buffer, inputPtr, input.length);
58
+ inputHeap.set(input);
59
+
60
+ var ouputSize = bitmap.width.value * bitmap.height.value * 4;
61
+ var outputPtr = rle._malloc(ouputSize);
62
+
63
+ var outputHeap = new Uint8Array(rle.HEAPU8.buffer, outputPtr, ouputSize);
64
+
65
+ var res = rle.ccall(fName,
66
+ 'number',
67
+ ['number', 'number', 'number', 'number', 'number', 'number', 'number', 'number'],
68
+ [outputHeap.byteOffset, bitmap.width.value, bitmap.height.value, bitmap.width.value, bitmap.height.value, inputHeap.byteOffset, input.length]
69
+ );
70
+
71
+ var output = new Uint8ClampedArray(outputHeap.buffer, outputHeap.byteOffset, ouputSize);
72
+
73
+ rle._free(inputPtr);
74
+ rle._free(outputPtr);
75
+
76
+ return output;
77
}
78
79
/**
80
* Main RDP module
81
*/
82
function RdpClient(config) {
83
- config = config || {};
84
- this.connected = false;
85
- this.bufferLayer = new layer.BufferLayer(new net.Socket());
86
- this.tpkt = new TPKT(this.bufferLayer);
87
- this.x224 = new x224.Client(this.tpkt, config);
88
- this.mcs = new t125.mcs.Client(this.x224);
89
- this.sec = new pdu.sec.Client(this.mcs, this.tpkt);
90
- this.global = new pdu.global.Client(this.sec, this.sec);
91
-
92
- // config log level
93
- log.level = log.Levels[config.logLevel || 'INFO'] || log.Levels.INFO;
94
-
95
- // credentials
96
- if (config.domain) {
97
- this.sec.infos.obj.domain.value = Buffer.from(config.domain + '\x00', 'ucs2');
98
- }
99
- if (config.userName) {
100
- this.sec.infos.obj.userName.value = Buffer.from(config.userName + '\x00', 'ucs2');
101
- }
102
- if (config.password) {
103
- this.sec.infos.obj.password.value = Buffer.from(config.password + '\x00', 'ucs2');
104
- }
105
- if(config.workingDir) {
106
- this.sec.infos.obj.workingDir.value = Buffer.from(config.workingDir + '\x00', 'ucs2');
107
- }
108
- if(config.alternateShell) {
109
- this.sec.infos.obj.alternateShell.value = Buffer.from(config.alternateShell + '\x00', 'ucs2');
110
- }
83
+ config = config || {};
84
+ this.connected = false;
85
+ this.bufferLayer = new layer.BufferLayer(new net.Socket());
86
+ this.tpkt = new TPKT(this.bufferLayer);
87
+ this.x224 = new x224.Client(this.tpkt, config);
88
+ this.mcs = new t125.mcs.Client(this.x224);
89
+ this.sec = new pdu.sec.Client(this.mcs, this.tpkt);
90
+ this.global = new pdu.global.Client(this.sec, this.sec);
91
+
92
+ // config log level
93
+ log.level = log.Levels[config.logLevel || 'INFO'] || log.Levels.INFO;
94
+
95
+ // credentials
96
+ if (config.domain) {
97
+ this.sec.infos.obj.domain.value = Buffer.from(config.domain + '\x00', 'ucs2');
98
+ }
99
+ if (config.userName) {
100
+ this.sec.infos.obj.userName.value = Buffer.from(config.userName + '\x00', 'ucs2');
101
+ }
102
+ if (config.password) {
103
+ this.sec.infos.obj.password.value = Buffer.from(config.password + '\x00', 'ucs2');
104
+ }
105
+ if (config.workingDir) {
106
+ this.sec.infos.obj.workingDir.value = Buffer.from(config.workingDir + '\x00', 'ucs2');
107
+ }
108
+ if (config.alternateShell) {
109
+ this.sec.infos.obj.alternateShell.value = Buffer.from(config.alternateShell + '\x00', 'ucs2');
110
+ }
111
112
if (config.perfFlags != null) {
113
this.sec.infos.obj.extendedInfo.obj.performanceFlags.value = config.perfFlags;
@@ -121,72 +121,72 @@ function RdpClient(config) {
121
| pdu.sec.PerfFlag.PERF_DISABLE_FULLWINDOWDRAG;
122
}
123
}
124
-
125
- if (config.autoLogin) {
126
- this.sec.infos.obj.flag.value |= pdu.sec.InfoFlag.INFO_AUTOLOGON;
127
- }
128
-
129
- if (config.screen && config.screen.width && config.screen.height) {
130
- this.mcs.clientCoreData.obj.desktopWidth.value = config.screen.width;
131
- this.mcs.clientCoreData.obj.desktopHeight.value = config.screen.height;
132
- }
133
-
134
- log.debug('screen ' + this.mcs.clientCoreData.obj.desktopWidth.value + 'x' + this.mcs.clientCoreData.obj.desktopHeight.value);
135
-
136
- // config keyboard layout
137
- switch (config.locale) {
138
- case 'fr':
139
- log.debug('french keyboard layout');
140
- this.mcs.clientCoreData.obj.kbdLayout.value = t125.gcc.KeyboardLayout.FRENCH;
141
- break;
142
- case 'en':
143
- default:
144
- log.debug('english keyboard layout');
145
- this.mcs.clientCoreData.obj.kbdLayout.value = t125.gcc.KeyboardLayout.US;
146
- }
147
-
148
-
149
- //bind all events
150
- var self = this;
151
- this.global.on('connect', function () {
152
- self.connected = true;
153
- self.emit('connect');
154
- }).on('session', function () {
155
- self.emit('session');
156
- }).on('close', function () {
157
- self.connected = false;
158
- self.emit('close');
159
- }).on('bitmap', function (bitmaps) {
160
- for(var bitmap in bitmaps) {
161
- var bitmapData = bitmaps[bitmap].obj.bitmapDataStream.value;
162
- var isCompress = bitmaps[bitmap].obj.flags.value & pdu.data.BitmapFlag.BITMAP_COMPRESSION;
163
-
164
- if (isCompress && config.decompress) {
165
- bitmapData = decompress(bitmaps[bitmap].obj);
166
- isCompress = false;
167
- }
168
-
169
- self.emit('bitmap', {
170
- destTop : bitmaps[bitmap].obj.destTop.value,
171
- destLeft : bitmaps[bitmap].obj.destLeft.value,
172
- destBottom : bitmaps[bitmap].obj.destBottom.value,
173
- destRight : bitmaps[bitmap].obj.destRight.value,
174
- width : bitmaps[bitmap].obj.width.value,
175
- height : bitmaps[bitmap].obj.height.value,
176
- bitsPerPixel : bitmaps[bitmap].obj.bitsPerPixel.value,
177
- isCompress : isCompress,
178
- data : bitmapData
179
- });
180
- }
181
- }).on('error', function (err) {
182
- log.warn(err.code + '(' + err.message + ')\n' + err.stack);
183
- if (err instanceof error.FatalError) {
184
- throw err;
185
- }
186
- else {
187
- self.emit('error', err);
188
- }
189
- });
124
+
125
+ if (config.autoLogin) {
126
+ this.sec.infos.obj.flag.value |= pdu.sec.InfoFlag.INFO_AUTOLOGON;
127
+ }
128
+
129
+ if (config.screen && config.screen.width && config.screen.height) {
130
+ this.mcs.clientCoreData.obj.desktopWidth.value = config.screen.width;
131
+ this.mcs.clientCoreData.obj.desktopHeight.value = config.screen.height;
132
+ }
133
+
134
+ log.debug('screen ' + this.mcs.clientCoreData.obj.desktopWidth.value + 'x' + this.mcs.clientCoreData.obj.desktopHeight.value);
135
+
136
+ // config keyboard layout
137
+ switch (config.locale) {
138
+ case 'fr':
139
+ log.debug('french keyboard layout');
140
+ this.mcs.clientCoreData.obj.kbdLayout.value = t125.gcc.KeyboardLayout.FRENCH;
141
+ break;
142
+ case 'en':
143
+ default:
144
+ log.debug('english keyboard layout');
145
+ this.mcs.clientCoreData.obj.kbdLayout.value = t125.gcc.KeyboardLayout.US;
146
+ }
147
+
148
+
149
+ //bind all events
150
+ var self = this;
151
+ this.global.on('connect', function () {
152
+ self.connected = true;
153
+ self.emit('connect');
154
+ }).on('session', function () {
155
+ self.emit('session');
156
+ }).on('close', function () {
157
+ self.connected = false;
158
+ self.emit('close');
159
+ }).on('bitmap', function (bitmaps) {
160
+ for (var bitmap in bitmaps) {
161
+ var bitmapData = bitmaps[bitmap].obj.bitmapDataStream.value;
162
+ var isCompress = bitmaps[bitmap].obj.flags.value & pdu.data.BitmapFlag.BITMAP_COMPRESSION;
163
+
164
+ if (isCompress && config.decompress) {
165
+ bitmapData = decompress(bitmaps[bitmap].obj);
166
+ isCompress = false;
167
+ }
168
+
169
+ self.emit('bitmap', {
170
+ destTop: bitmaps[bitmap].obj.destTop.value,
171
+ destLeft: bitmaps[bitmap].obj.destLeft.value,
172
+ destBottom: bitmaps[bitmap].obj.destBottom.value,
173
+ destRight: bitmaps[bitmap].obj.destRight.value,
174
+ width: bitmaps[bitmap].obj.width.value,
175
+ height: bitmaps[bitmap].obj.height.value,
176
+ bitsPerPixel: bitmaps[bitmap].obj.bitsPerPixel.value,
177
+ isCompress: isCompress,
178
+ data: bitmapData
179
+ });
180
+ }
181
+ }).on('error', function (err) {
182
+ log.warn(err.code + '(' + err.message + ')\n' + err.stack);
183
+ if (err instanceof error.FatalError) {
184
+ throw err;
185
+ }
186
+ else {
187
+ self.emit('error', err);
188
+ }
189
+ });
190
}
191
192
inherits(RdpClient, events.EventEmitter);
@@ -197,24 +197,24 @@ inherits(RdpClient, events.EventEmitter);
197
* @param port {integer} destination port
198
*/
199
RdpClient.prototype.connect = function (host, port) {
200
- log.debug('connect to ' + host + ':' + port);
201
- var self = this;
202
- this.bufferLayer.socket.connect(port, host, function () {
203
- // in client mode connection start from x224 layer
204
- self.x224.connect();
205
- });
206
- return this;
200
+ log.debug('connect to ' + host + ':' + port);
201
+ var self = this;
202
+ this.bufferLayer.socket.connect(port, host, function () {
203
+ // in client mode connection start from x224 layer
204
+ self.x224.connect();
205
+ });
206
+ return this;
207
};
208
209
/**
210
* Close RDP client
211
*/
212
RdpClient.prototype.close = function () {
213
- if(this.connected) {
214
- this.global.close();
215
- }
216
- this.connected = false;
217
- return this;
213
+ if (this.connected) {
214
+ this.global.close();
215
+ }
216
+ this.connected = false;
217
+ return this;
218
};
219
220
/**
@@ -225,31 +225,31 @@ RdpClient.prototype.close = function () {
225
* @param isPressed {boolean} state of button
226
*/
227
RdpClient.prototype.sendPointerEvent = function (x, y, button, isPressed) {
228
- if (!this.connected)
229
- return;
230
-
231
- var event = pdu.data.pointerEvent();
232
- if (isPressed) {
233
- event.obj.pointerFlags.value |= pdu.data.PointerFlag.PTRFLAGS_DOWN;
234
- }
235
-
236
- switch(button) {
237
- case 1:
238
- event.obj.pointerFlags.value |= pdu.data.PointerFlag.PTRFLAGS_BUTTON1;
239
- break;
240
- case 2:
241
- event.obj.pointerFlags.value |= pdu.data.PointerFlag.PTRFLAGS_BUTTON2;
242
- break;
243
- case 3:
244
- event.obj.pointerFlags.value |= pdu.data.PointerFlag.PTRFLAGS_BUTTON3
245
- break;
246
- default:
247
- event.obj.pointerFlags.value |= pdu.data.PointerFlag.PTRFLAGS_MOVE;
248
- }
249
-
228
+ if (!this.connected)
229
+ return;
230
+
231
+ var event = pdu.data.pointerEvent();
232
+ if (isPressed) {
233
+ event.obj.pointerFlags.value |= pdu.data.PointerFlag.PTRFLAGS_DOWN;
234
+ }
235
+
236
+ switch (button) {
237
+ case 1:
238
+ event.obj.pointerFlags.value |= pdu.data.PointerFlag.PTRFLAGS_BUTTON1;
239
+ break;
240
+ case 2:
241
+ event.obj.pointerFlags.value |= pdu.data.PointerFlag.PTRFLAGS_BUTTON2;
242
+ break;
243
+ case 3:
244
+ event.obj.pointerFlags.value |= pdu.data.PointerFlag.PTRFLAGS_BUTTON3
245
+ break;
246
+ default:
247
+ event.obj.pointerFlags.value |= pdu.data.PointerFlag.PTRFLAGS_MOVE;
248
+ }
249
+
250
event.obj.xPos.value = x;
251
event.obj.yPos.value = y;
252
-
252
+
253
this.global.sendInputEvents([event]);
254
};
255
@@ -260,20 +260,20 @@ RdpClient.prototype.sendPointerEvent = function (x, y, button, isPressed) {
260
* @param extended {boolenan} extended keys
261
*/
262
RdpClient.prototype.sendKeyEventScancode = function (code, isPressed, extended) {
263
- if (!this.connected)
264
- return;
265
- extended = extended || false;
266
- var event = pdu.data.scancodeKeyEvent();
267
- event.obj.keyCode.value = code;
268
-
269
- if (!isPressed) {
270
- event.obj.keyboardFlags.value |= pdu.data.KeyboardFlag.KBDFLAGS_RELEASE;
271
- }
272
-
263
+ if (!this.connected)
264
+ return;
265
+ extended = extended || false;
266
+ var event = pdu.data.scancodeKeyEvent();
267
+ event.obj.keyCode.value = code;
268
+
269
+ if (!isPressed) {
270
+ event.obj.keyboardFlags.value |= pdu.data.KeyboardFlag.KBDFLAGS_RELEASE;
271
+ }
272
+
273
if (extended) {
274
- event.obj.keyboardFlags.value |= pdu.data.KeyboardFlag.KBDFLAGS_EXTENDED;
274
+ event.obj.keyboardFlags.value |= pdu.data.KeyboardFlag.KBDFLAGS_EXTENDED;
275
}
276
-
276
+
277
this.global.sendInputEvents([event]);
278
};
279
@@ -283,16 +283,16 @@ RdpClient.prototype.sendKeyEventScancode = function (code, isPressed, extended)
283
* @param isPressed {boolean}
284
*/
285
RdpClient.prototype.sendKeyEventUnicode = function (code, isPressed) {
286
- if (!this.connected)
287
- return;
288
-
289
- var event = pdu.data.unicodeKeyEvent();
290
- event.obj.unicode.value = code;
291
-
292
- if (!isPressed) {
293
- event.obj.keyboardFlags.value |= pdu.data.KeyboardFlag.KBDFLAGS_RELEASE;
294
- }
295
- this.global.sendInputEvents([event]);
286
+ if (!this.connected)
287
+ return;
288
+
289
+ var event = pdu.data.unicodeKeyEvent();
290
+ event.obj.unicode.value = code;
291
+
292
+ if (!isPressed) {
293
+ event.obj.keyboardFlags.value |= pdu.data.KeyboardFlag.KBDFLAGS_RELEASE;
294
+ }
295
+ this.global.sendInputEvents([event]);
296
}
297
298
/**
@@ -304,32 +304,32 @@ RdpClient.prototype.sendKeyEventUnicode = function (code, isPressed) {
304
* @param isHorizontal {boolean}
305
*/
306
RdpClient.prototype.sendWheelEvent = function (x, y, step, isNegative, isHorizontal) {
307
- if (!this.connected)
308
- return;
309
-
310
- var event = pdu.data.pointerEvent();
311
- if (isHorizontal) {
307
+ if (!this.connected)
308
+ return;
309
+
310
+ var event = pdu.data.pointerEvent();
311
+ if (isHorizontal) {
312
event.obj.pointerFlags.value |= pdu.data.PointerFlag.PTRFLAGS_HWHEEL;
313
- }
313
+ }
314
else {
315
- event.obj.pointerFlags.value |= pdu.data.PointerFlag.PTRFLAGS_WHEEL;
315
+ event.obj.pointerFlags.value |= pdu.data.PointerFlag.PTRFLAGS_WHEEL;
316
}
317
-
318
-
319
- if (isNegative) {
317
+
318
+
319
+ if (isNegative) {
320
event.obj.pointerFlags.value |= pdu.data.PointerFlag.PTRFLAGS_WHEEL_NEGATIVE;
321
- }
322
-
321
+ }
322
+
323
event.obj.pointerFlags.value |= (step & pdu.data.PointerFlag.WheelRotationMask)
324
-
324
+
325
event.obj.xPos.value = x;
326
event.obj.yPos.value = y;
327
-
327
+
328
this.global.sendInputEvents([event]);
329
}
330
331
function createClient(config) {
332
- return new RdpClient(config);
332
+ return new RdpClient(config);
333
};
334
335
/**
@@ -338,28 +338,28 @@ function createClient(config) {
338
* @param socket {net.Socket}
339
*/
340
function RdpServer(config, socket) {
341
- if (!(config.key && config.cert)) {
342
- throw new error.FatalError('NODE_RDP_PROTOCOL_RDP_SERVER_CONFIG_MISSING', 'missing cryptographic tools')
343
- }
344
- this.connected = false;
345
- this.bufferLayer = new layer.BufferLayer(socket);
346
- this.tpkt = new TPKT(this.bufferLayer);
347
- this.x224 = new x224.Server(this.tpkt, config.key, config.cert);
348
- this.mcs = new t125.mcs.Server(this.x224);
341
+ if (!(config.key && config.cert)) {
342
+ throw new error.FatalError('NODE_RDP_PROTOCOL_RDP_SERVER_CONFIG_MISSING', 'missing cryptographic tools')
343
+ }
344
+ this.connected = false;
345
+ this.bufferLayer = new layer.BufferLayer(socket);
346
+ this.tpkt = new TPKT(this.bufferLayer);
347
+ this.x224 = new x224.Server(this.tpkt, config.key, config.cert);
348
+ this.mcs = new t125.mcs.Server(this.x224);
349
};
350
351
inherits(RdpServer, events.EventEmitter);
352
353
-function createServer (config, next) {
354
- return net.createServer(function (socket) {
355
- next(new RdpServer(config, socket));
356
- });
353
+function createServer(config, next) {
354
+ return net.createServer(function (socket) {
355
+ next(new RdpServer(config, socket));
356
+ });
357
};
358
359
/**
360
* Module exports
361
*/
362
module.exports = {
363
- createClient : createClient,
364
- createServer : createServer
363
+ createClient: createClient,
364
+ createServer: createServer
365
};
\ No newline at end of file
views/default.handlebars
+16
-5
@@ -1379,6 +1379,10 @@
1379
<input id="idx_dlgCancelButton" type="button" value="Cancel" style="" onclick="dialogclose(0)" />
1380
<input id="idx_dlgOkButton" type="button" value="OK" style="" onclick="dialogclose(1)" />
1381
<div><input id="idx_dlgDeleteButton" type="button" value="Delete" style="display:none" onclick="dialogclose(2)" /></div>
1382
+ <div id="idx_dlgMoreButtons">
1383
+ <a href=# id=morexxx1 style=cursor:pointer;color:gray;text-decoration:none title="Toggle advanced options" onclick=MoreToggle(true)>▼</a>
1384
+ <a href=# id=morexxx2 style=cursor:pointer;color:gray;text-decoration:none title="Toggle advanced options" onclick=MoreToggle(false)>▲</a>
1385
+ </div>
1386
</div>
1387
</div>
1388
<iframe name="fileUploadFrame" style="display:none"></iframe>
@@ -8552,7 +8556,11 @@
8556
x += addHtmlValue("Username", '<input type=text id=d2user style=width:230px onKeyUp=askRdpCredentialsValidate() maxlength=128 />');
8557
x += addHtmlValue("Password", '<input type=password id=d2pass style=width:230px maxlength=128 autocomplete=off />');
8558
if ((features2 & 0x00400000) == 0) { x += addHtmlValue("", '<label><input type="checkbox" id=d2savecred>' + "Remember credentials" + '</label>'); }
8555
- x + '</div></div>';
8559
+ x += '</div>';
8560
+ x += MoreStart();
8561
+ x += addHtmlValue("Alt Shell", '<input type=text id=d2altshell style=width:230px maxlength=2048 />');
8562
+ x += addHtmlValue("Working Dir", '<input type=text id=d2workdir style=width:230px maxlength=2048 />');
8563
+ x += MoreEnd();
8564
setDialogMode(2, "RDP Credentials", 3, askRdpCredentialsEx, x);
8565
}
8566
@@ -8586,11 +8594,11 @@
8594
height = Q('DeskParent').offsetHeight;
8595
}
8596
if ((currentNode.rdp == 1) && (Q('d2mode').value == 1)) {
8589
- connectDesktop(null, 4, { servercred: true, width: width, height: height, flags: (desktopsettings.rdpflags != null) ? desktopsettings.rdpflags : 0x2F });
8597
+ connectDesktop(null, 4, { servercred: true, width: width, height: height, flags: (desktopsettings.rdpflags != null) ? desktopsettings.rdpflags : 0x2F, altshell: Q('d2altshell').value, workdir: Q('d2workdir').value });
8598
} else {
8599
var savecred = false;
8600
if ((features2 & 0x00400000) == 0) { savecred = Q('d2savecred').checked; }
8593
- connectDesktop(null, 4, { domain: Q('d2domain').value, username: Q('d2user').value, password: Q('d2pass').value, savecred: savecred, width: width, height: height, flags: (desktopsettings.rdpflags != null) ? desktopsettings.rdpflags : 0x2F });
8601
+ connectDesktop(null, 4, { domain: Q('d2domain').value, username: Q('d2user').value, password: Q('d2pass').value, savecred: savecred, width: width, height: height, flags: (desktopsettings.rdpflags != null) ? desktopsettings.rdpflags : 0x2F, altshell: Q('d2altshell').value, workdir: Q('d2workdir').value });
8602
}
8603
}
8604
@@ -16857,6 +16865,7 @@
16865
16866
// Reset dialog size
16867
QS('dialog').width = QS('dialog').top = QS('dialog').left = QS('dialog').right = QS('dialog').bottom = null;
16868
+ MoreToggle(false);
16869
16870
QE('idx_dlgOkButton', true);
16871
QV('idx_dlgOkButton', b & 1);
@@ -16869,6 +16878,7 @@
16878
for (var i = 1; i < 24; i++) { QV('dialog' + i, i == x); } // Edit this line when more dialogs are added
16879
QV('dialog', x);
16880
if (c) { if (x == 2) { QH('id_dialogOptions', c); } else { QH('id_dialogMessage', c); } }
16881
+ QV('idx_dlgMoreButtons', (Q('morexxx3') != null));
16882
}
16883
16884
function dialogclose(x) {
@@ -17470,8 +17480,9 @@
17480
function AddButton(v, f) { return '<input type=button value="' + v + '" onclick="' + f + '" style=margin:4px>'; }
17481
function AddButton2(v, f) { return '<input type=button value="' + v + '" onclick="' + f + '">'; }
17482
function AddRefreshButton(f) { return '<input type=button name=refreshbtn value=Refresh onclick="refreshButtons(false);' + f + '" style=margin:4px ' + (refreshButtonsState==false?'disabled':'') + '>'; }
17473
- function MoreStart() { return '<a href=# style=cursor:pointer;color:blue id=morexxx1 onclick=QV("morexxx1",false);QV("morexxx2",true)>▼ ' + "More" + '</a><div id=morexxx2 style=display:none><br><hr>'; };
17474
- function MoreEnd() { return '<a href=# style=cursor:pointer;color:blue onclick=QV("morexxx2",false);QV("morexxx1",true)>▲ ' + "Less" + '</a></div>'; };
17483
+ function MoreStart() { return '<div id=morexxx3 style=display:none><hr>'; };
17484
+ function MoreEnd() { return '</div>'; };
17485
+ function MoreToggle(v) { QV("morexxx1",!v); QV("morexxx2",v); QV("morexxx3",v); }
17486
function getSelectedOptions(sel) { var opts = [], opt; for (var i = 0, len = sel.options.length; i < len; i++) { opt = sel.options[i]; if (opt.selected) { opts.push(opt.value); } } return opts; }
17487
function getInstance(x, y) { for (var i in x) { if (x[i]['InstanceID'] == y) return x[i]; } return null; }
17488
function getItem(x, y, z) { for (var i in x) { if (x[i][y] == z) return x[i]; } return null; }