1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim:expandtab:shiftwidth=2:tabstop=2:
3 */
4 /* This Source Code Form is subject to the terms of the Mozilla Public
5 * License, v. 2.0. If a copy of the MPL was not distributed with this
6 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7
8 #include "nsUnixRemoteServer.h"
9 #include "nsGTKToolkit.h"
10 #include "nsCOMPtr.h"
11 #include "nsICommandLineRunner.h"
12 #include "nsCommandLine.h"
13 #include "nsIFile.h"
14
15 // Set desktop startup ID to the passed ID, if there is one, so that any created
16 // windows get created with the right window manager metadata, and any windows
17 // that get new tabs and are activated also get the right WM metadata.
18 // The timestamp will be used if there is no desktop startup ID, or if we're
19 // raising an existing window rather than showing a new window for the first
20 // time.
SetDesktopStartupIDOrTimestamp(const nsACString & aDesktopStartupID,uint32_t aTimestamp)21 void nsUnixRemoteServer::SetDesktopStartupIDOrTimestamp(
22 const nsACString& aDesktopStartupID, uint32_t aTimestamp) {
23 nsGTKToolkit* toolkit = nsGTKToolkit::GetToolkit();
24 if (!toolkit) return;
25
26 if (!aDesktopStartupID.IsEmpty()) {
27 toolkit->SetDesktopStartupID(aDesktopStartupID);
28 }
29
30 toolkit->SetFocusTimestamp(aTimestamp);
31 }
32
FindExtensionParameterInCommand(const char * aParameterName,const nsACString & aCommand,char aSeparator,nsACString * aValue)33 static bool FindExtensionParameterInCommand(const char* aParameterName,
34 const nsACString& aCommand,
35 char aSeparator,
36 nsACString* aValue) {
37 nsAutoCString searchFor;
38 searchFor.Append(aSeparator);
39 searchFor.Append(aParameterName);
40 searchFor.Append('=');
41
42 nsACString::const_iterator start, end;
43 aCommand.BeginReading(start);
44 aCommand.EndReading(end);
45 if (!FindInReadable(searchFor, start, end)) return false;
46
47 nsACString::const_iterator charStart, charEnd;
48 charStart = end;
49 aCommand.EndReading(charEnd);
50 nsACString::const_iterator idStart = charStart, idEnd;
51 if (FindCharInReadable(aSeparator, charStart, charEnd)) {
52 idEnd = charStart;
53 } else {
54 idEnd = charEnd;
55 }
56 *aValue = nsDependentCSubstring(idStart, idEnd);
57 return true;
58 }
59
HandleCommandLine(const char * aBuffer,uint32_t aTimestamp)60 const char* nsUnixRemoteServer::HandleCommandLine(const char* aBuffer,
61 uint32_t aTimestamp) {
62 nsCOMPtr<nsICommandLineRunner> cmdline(new nsCommandLine());
63
64 // the commandline property is constructed as an array of int32_t
65 // followed by a series of null-terminated strings:
66 //
67 // [argc][offsetargv0][offsetargv1...]<workingdir>\0<argv[0]>\0argv[1]...\0
68 // (offset is from the beginning of the buffer)
69
70 int32_t argc = TO_LITTLE_ENDIAN32(*reinterpret_cast<const int32_t*>(aBuffer));
71 const char* wd = aBuffer + ((argc + 1) * sizeof(int32_t));
72
73 nsCOMPtr<nsIFile> lf;
74 nsresult rv =
75 NS_NewNativeLocalFile(nsDependentCString(wd), true, getter_AddRefs(lf));
76 if (NS_FAILED(rv)) return "509 internal error";
77
78 nsAutoCString desktopStartupID;
79
80 const char** argv = (const char**)malloc(sizeof(char*) * argc);
81 if (!argv) return "509 internal error";
82
83 const int32_t* offset = reinterpret_cast<const int32_t*>(aBuffer) + 1;
84
85 for (int i = 0; i < argc; ++i) {
86 argv[i] = aBuffer + TO_LITTLE_ENDIAN32(offset[i]);
87
88 if (i == 0) {
89 nsDependentCString cmd(argv[0]);
90 FindExtensionParameterInCommand("DESKTOP_STARTUP_ID", cmd, ' ',
91 &desktopStartupID);
92 }
93 }
94
95 rv = cmdline->Init(argc, argv, lf, nsICommandLine::STATE_REMOTE_AUTO);
96
97 free(argv);
98 if (NS_FAILED(rv)) {
99 return "509 internal error";
100 }
101
102 SetDesktopStartupIDOrTimestamp(desktopStartupID, aTimestamp);
103
104 rv = cmdline->Run();
105
106 if (NS_ERROR_ABORT == rv) return "500 command not parseable";
107
108 if (NS_FAILED(rv)) return "509 internal error";
109
110 return "200 executed command";
111 }
112