summaryrefslogtreecommitdiffstats
path: root/cloud_print/virtual_driver
diff options
context:
space:
mode:
authorabeera@google.com <abeera@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2011-08-19 04:14:58 +0000
committerabeera@google.com <abeera@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2011-08-19 04:14:58 +0000
commit23a96d057f6f59497b27050e95d2d01699cf8981 (patch)
tree448c8d3e765e5cff7b9b93a919dbc981e3472dc8 /cloud_print/virtual_driver
parent64cecfd77eaa9c61a1d9039fe4b1f2387aaab3cb (diff)
downloadchromium_src-23a96d057f6f59497b27050e95d2d01699cf8981.zip
chromium_src-23a96d057f6f59497b27050e95d2d01699cf8981.tar.gz
chromium_src-23a96d057f6f59497b27050e95d2d01699cf8981.tar.bz2
Simplify the Posix Cloud Print virtual driver, add print ticket support for Mac and Linux.
BUG=NONE TEST= NONE Review URL: http://codereview.chromium.org/7612004 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@97423 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'cloud_print/virtual_driver')
-rw-r--r--cloud_print/virtual_driver/posix/backend.gyp16
-rw-r--r--cloud_print/virtual_driver/posix/printer_driver_util_linux.cc11
-rw-r--r--cloud_print/virtual_driver/posix/printer_driver_util_mac.mm10
-rw-r--r--cloud_print/virtual_driver/posix/printer_driver_util_posix.cc99
-rw-r--r--cloud_print/virtual_driver/posix/printer_driver_util_posix.h12
-rw-r--r--cloud_print/virtual_driver/posix/virtual_driver_posix.cc108
-rw-r--r--cloud_print/virtual_driver/posix/virtual_driver_posix_tests.cc75
-rw-r--r--cloud_print/virtual_driver/virtual_driver_switches.cc1
-rw-r--r--cloud_print/virtual_driver/virtual_driver_switches.h5
9 files changed, 253 insertions, 84 deletions
diff --git a/cloud_print/virtual_driver/posix/backend.gyp b/cloud_print/virtual_driver/posix/backend.gyp
index df6e49b..ae65801 100644
--- a/cloud_print/virtual_driver/posix/backend.gyp
+++ b/cloud_print/virtual_driver/posix/backend.gyp
@@ -15,10 +15,12 @@
],
'sources': [
'printer_driver_util_linux.cc',
+ 'printer_driver_util_posix.cc',
'printer_driver_util_posix.h',
'printer_driver_util_mac.mm',
'virtual_driver_posix.cc',
'../virtual_driver_switches.cc',
+ '../virtual_driver_switches.h',
],
'conditions': [
['OS=="mac"', {
@@ -26,6 +28,20 @@
'libraries': ['ScriptingBridge.framework'],
}],
],
+ },
+ {
+ 'target_name': 'virtual_driver_posix_unittests',
+ 'type': 'executable',
+ 'dependencies': [
+ '../../../base/base.gyp:base',
+ '../../../base/base.gyp:test_support_base',
+ '../../../testing/gmock.gyp:gmock',
+ '../../../testing/gtest.gyp:gtest',
+ ],
+ 'sources': [
+ 'virtual_driver_posix_tests.cc',
+ 'printer_driver_util_posix.cc',
+ ],
}],
'conditions': [
['OS=="mac"', {
diff --git a/cloud_print/virtual_driver/posix/printer_driver_util_linux.cc b/cloud_print/virtual_driver/posix/printer_driver_util_linux.cc
index 81014f8..b7e70cf 100644
--- a/cloud_print/virtual_driver/posix/printer_driver_util_linux.cc
+++ b/cloud_print/virtual_driver/posix/printer_driver_util_linux.cc
@@ -13,9 +13,12 @@
#include "cloud_print/virtual_driver/posix/printer_driver_util_posix.h"
#include "cloud_print/virtual_driver/virtual_driver_switches.h"
+namespace printer_driver_util {
+
void LaunchPrintDialog(const std::string& output_path,
const std::string& job_title,
- const std::string& current_user) {
+ const std::string& current_user,
+ const std::string& print_ticket) {
std::string set_var;
// Set Environment variable to control display.
@@ -28,15 +31,15 @@ void LaunchPrintDialog(const std::string& output_path,
}
// Construct the call to Chrome
-
FilePath chrome_path("google-chrome");
FilePath job_path(output_path);
CommandLine command_line(chrome_path);
command_line.AppendSwitchPath(switches::kCloudPrintFile, job_path);
command_line.AppendSwitchNative(switches::kCloudPrintJobTitle, job_title);
command_line.AppendSwitch(switches::kCloudPrintDeleteFile);
+ command_line.AppendSwitchNative(switches::kCloudPrintPrintTicket,
+ print_ticket);
LOG(INFO) << "Call to chrome is " << command_line.GetCommandLineString();
-
if (system(command_line.GetCommandLineString().c_str()) == -1) {
LOG(ERROR) << "Unable to call Chrome";
exit(CUPS_BACKEND_CANCEL);
@@ -44,3 +47,5 @@ void LaunchPrintDialog(const std::string& output_path,
LOG(INFO) << "Call to Chrome succeeded";
}
+} // namespace printer_driver_util
+
diff --git a/cloud_print/virtual_driver/posix/printer_driver_util_mac.mm b/cloud_print/virtual_driver/posix/printer_driver_util_mac.mm
index d85e3ff..b17788d 100644
--- a/cloud_print/virtual_driver/posix/printer_driver_util_mac.mm
+++ b/cloud_print/virtual_driver/posix/printer_driver_util_mac.mm
@@ -34,9 +34,11 @@ bool IsBrowserRunning(std::string bundleID) {
}
} // namespace cloud_print
+namespace printer_driver_util {
void LaunchPrintDialog(const std::string& outputPath,
const std::string& jobTitle,
- const std::string& user) {
+ const std::string& user,
+ const std::string& print_ticket) {
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
OSStatus status = noErr;
FSRef ref;
@@ -84,6 +86,9 @@ void LaunchPrintDialog(const std::string& outputPath,
[NSString stringWithUTF8String:jobTitle.c_str()]];
NSAppleEventDescriptor* mime = [NSAppleEventDescriptor
descriptorWithString:@"application/pdf"];
+ NSAppleEventDescriptor* ticket =
+ [NSAppleEventDescriptor descriptorWithString:
+ [NSString stringWithUTF8String:print_ticket.c_str()]];
// Create and populate the list of parameters.
// Note that the array starts at index 1.
@@ -97,6 +102,7 @@ void LaunchPrintDialog(const std::string& outputPath,
[parameters insertDescriptor:mime atIndex:1];
[parameters insertDescriptor:printPath atIndex:2];
[parameters insertDescriptor:title atIndex:3];
+ [parameters insertDescriptor:ticket atIndex:4];
[event setParamDescriptor:parameters forKeyword:kAECloudPrintClass];
// Set the application launch parameters.
@@ -118,3 +124,5 @@ void LaunchPrintDialog(const std::string& outputPath,
[pool release];
return;
}
+
+} // namespace printer_driver_util
diff --git a/cloud_print/virtual_driver/posix/printer_driver_util_posix.cc b/cloud_print/virtual_driver/posix/printer_driver_util_posix.cc
new file mode 100644
index 0000000..d78f632
--- /dev/null
+++ b/cloud_print/virtual_driver/posix/printer_driver_util_posix.cc
@@ -0,0 +1,99 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <pwd.h>
+#include <stdio.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+#include <cups/backend.h>
+
+#include "base/json/json_writer.h"
+#include "base/logging.h"
+#include "base/string_tokenizer.h"
+#include "base/values.h"
+
+#include "cloud_print/virtual_driver/posix/printer_driver_util_posix.h"
+
+namespace printer_driver_util {
+
+void WriteToTemp(FILE* input_pdf, FilePath output_path) {
+ FILE* output_pdf;
+ char buffer[128];
+ output_pdf = fopen(output_path.value().c_str(), "w");
+ if (output_pdf == NULL) {
+ LOG(ERROR) << "Unable to open file handle for writing output file";
+ exit(CUPS_BACKEND_CANCEL);
+ }
+ // Read from input file or stdin and write to output file.
+ while (fgets(buffer, sizeof(buffer), input_pdf) != NULL) {
+ fputs(buffer, output_pdf);
+ }
+
+ LOG(INFO) << "Successfully wrote output file";
+ // ensure everything is written, then close the files.
+ fflush(output_pdf);
+ fclose(input_pdf);
+ fclose(output_pdf);
+}
+
+// Sets the UID of the process to that of the username.
+void SetUser(const char* user) {
+ struct passwd* calling_user = NULL;
+ calling_user = getpwnam(user);
+ if (calling_user == NULL) {
+ LOG(ERROR) << "Unable to get calling user";
+ exit(CUPS_BACKEND_CANCEL);
+ }
+ if (!setuid(calling_user->pw_uid) == -1) {
+ LOG(ERROR) << "Unable to set UID";
+ exit(CUPS_BACKEND_CANCEL);
+ }
+
+ LOG(INFO) << "Successfully set user and group ID";
+}
+
+// Parses the options passed in on the command line to key value
+// JSON pairs. Assumes that the input options string is of the
+// format KEY=VALUE, with expressions being separated by spaces.
+// Fails if print_ticket cannot be written to.
+void GetOptions(const char* options, std::string* print_ticket) {
+ if (options == NULL) {
+ *(print_ticket) = "{}";
+ return;
+ }
+ CStringTokenizer t(options, options + strlen(options), " ");
+ DictionaryValue* json_options = new DictionaryValue;
+
+ while (t.GetNext()) {
+ std::string token = t.token();
+ // If the token ends with a slash, that indicates
+ // that the next space is actually escaped
+ // So we append the next token onto this token
+ // if possible. We also replace the slash with a space
+ // since the JSON will expect an unescaped string.
+ while (token.at(token.length()-1) == '\\') {
+ if (t.GetNext()) {
+ token.replace(token.length()-1, 1, " ");
+ token.append(t.token());
+ } else {
+ break;
+ }
+ }
+ size_t pos = token.find("=");
+ if (pos == std::string::npos) {
+ continue;
+ }
+ std::string option_name = token.substr(0, pos);
+ std::string option_value = token.substr(pos+1);
+ base::StringValue* val= base::Value::CreateStringValue(option_value);
+ json_options->SetWithoutPathExpansion(option_name, val);
+ }
+ base::JSONWriter::Write(json_options, /*pretty_print=*/false, print_ticket);
+ delete json_options;
+}
+
+} // namespace printer_driver_util
+
diff --git a/cloud_print/virtual_driver/posix/printer_driver_util_posix.h b/cloud_print/virtual_driver/posix/printer_driver_util_posix.h
index 821802b..8631f07 100644
--- a/cloud_print/virtual_driver/posix/printer_driver_util_posix.h
+++ b/cloud_print/virtual_driver/posix/printer_driver_util_posix.h
@@ -7,8 +7,18 @@
#include <string>
+#include "base/file_path.h"
+
+namespace printer_driver_util {
+
void LaunchPrintDialog(const std::string& output_path,
const std::string& job_title,
- const std::string& current_user);
+ const std::string& current_user,
+ const std::string& print_ticket);
+void WriteToTemp(FILE* input_pdf, FilePath output_path);
+void SetUser(const char* user);
+void GetOptions(const char* options, std::string* print_ticket);
+
+} // namespace printer_driver_util
#endif // CLOUD_PRINT_VIRTUAL_DRIVER_POSIX_PRINTER_DRIVER_UTIL_POSIX_H_
diff --git a/cloud_print/virtual_driver/posix/virtual_driver_posix.cc b/cloud_print/virtual_driver/posix/virtual_driver_posix.cc
index ec0a73d..aac6299 100644
--- a/cloud_print/virtual_driver/posix/virtual_driver_posix.cc
+++ b/cloud_print/virtual_driver/posix/virtual_driver_posix.cc
@@ -2,12 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include <pwd.h>
-#include <stdio.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-
#include <cups/backend.h>
#include "base/at_exit.h"
@@ -19,63 +13,28 @@
#include "cloud_print/virtual_driver/posix/printer_driver_util_posix.h"
-void WriteToTemp(FILE* input_pdf, FilePath output_path) {
- FILE* output_pdf;
- char buffer[128];
- output_pdf = fopen(output_path.value().c_str(), "w");
- if (output_pdf == NULL) {
- LOG(ERROR) << "Unable to open file handle for writing output file";
- exit(CUPS_BACKEND_CANCEL);
- }
- // Read from input file or stdin and write to output file.
- while (fgets(buffer, sizeof(buffer), input_pdf) != NULL) {
- fputs(buffer, output_pdf);
- }
-
- LOG(INFO) << "Successfully wrote output file";
- // ensure everything is written, then close the files.
- fflush(output_pdf);
- fclose(input_pdf);
- fclose(output_pdf);
-}
-
-void SetUser(const char* user) {
- struct passwd* calling_user = NULL;
- calling_user = getpwnam(user);
- if (calling_user == NULL) {
- LOG(ERROR) << "Unable to get calling user";
- exit(CUPS_BACKEND_CANCEL);
- }
- if (setgid(calling_user->pw_gid) == -1) {
- LOG(ERROR) << "Unable to set group ID";
- exit(CUPS_BACKEND_CANCEL);
- }
- if (!setuid(calling_user->pw_uid) == -1) {
- LOG(ERROR) << "Unable to set UID";
- exit(CUPS_BACKEND_CANCEL);
- }
-
- LOG(INFO) << "Successfully set user and group ID";
-}
-
-
-
// Main function for backend.
int main(int argc, const char* argv[]) {
// With no arguments, send identification string as required by CUPS.
if (argc == 1) {
printf("file GCP-driver:/ \"GCP Virtual Driver\" \"GCP Virtual Driver\" "
- "\"MFG:Google Inc.;MDL:GCP Virtual Driver;DES:GCP Virtual Driver;"
- "CLS:PRINTER;CMD:POSTSCRIPT;\"\n");
+ "\"MFG:Google Inc.;MDL:GCP Virtual Driver;DES:GCP Virtual Driver;"
+ "CLS:PRINTER;CMD:POSTSCRIPT;\"\n");
return 0;
}
if (argc < 6 || argc > 7) {
- fprintf(stderr, "Usage: GCP-Driver job-id user"
- "title copies options [file]\n");
+ fprintf(stderr, "Usage: GCP-Driver job-id user "
+ "title copies options [file]\n");
return 0;
}
+ // We can run the backend as root or unpriveliged user lp
+ // Since we want to launch the printer dialog as the user
+ // that initiated the print job, we run the backend as root
+ // and then setuid to the user that started the print job
+ printer_driver_util::SetUser(argv[2]);
+
// AtExitManager is necessary to use the path service.
base::AtExitManager aemanager;
// CommandLine is only setup to enable logging, never used subseqeuently.
@@ -85,10 +44,10 @@ int main(int argc, const char* argv[]) {
// Set up logging.
logging::InitLogging(log_location.c_str(),
- logging::LOG_ONLY_TO_FILE,
- logging::LOCK_LOG_FILE,
- logging::APPEND_TO_OLD_LOG_FILE,
- logging::DISABLE_DCHECK_FOR_NON_OFFICIAL_RELEASE_BUILDS);
+ logging::LOG_ONLY_TO_FILE,
+ logging::LOCK_LOG_FILE,
+ logging::APPEND_TO_OLD_LOG_FILE,
+ logging::DISABLE_DCHECK_FOR_NON_OFFICIAL_RELEASE_BUILDS);
// Temporary directory to hold the output file.
FilePath temp_dir;
@@ -98,6 +57,7 @@ int main(int argc, const char* argv[]) {
std::string job_title;
std::string job_id;
std::string file_name;
+ std::string print_ticket;
// Get temp directory to hold spool file.
if (!PathService::Get(base::DIR_TEMP, &temp_dir)) {
@@ -108,9 +68,15 @@ int main(int argc, const char* argv[]) {
current_user = argv[2];
job_title = argv[3];
job_id = argv[1];
+ printer_driver_util::GetOptions(argv[5], &print_ticket);
file_name = current_user + "-" + job_title + "-" + job_id;
FilePath output_path = temp_dir.Append(file_name);
+ // However, the input file can only be read as root.
+ if (!setuid(0)) {
+ PLOG(ERROR) << "Unable to setuid back to 0";
+ }
+
if (argc == 7) {
// Read from file if specified.
FILE* input_pdf = fopen(argv[6], "r");
@@ -119,34 +85,18 @@ int main(int argc, const char* argv[]) {
return CUPS_BACKEND_CANCEL;
}
// File is opened.
- WriteToTemp(input_pdf, output_path);
+ printer_driver_util::WriteToTemp(input_pdf, output_path);
} else {
// Otherwise, read from stdin.
- WriteToTemp(stdin, output_path);
- }
-
- // Set File permissions to allow non-sudo user to read spool file.
- if (chmod(output_path.value().c_str(),
- S_IRUSR|S_IWUSR|S_IROTH|S_IWOTH) != 0) {
- LOG(ERROR) << "Unable to change file permissions";
- return CUPS_BACKEND_CANCEL;
+ printer_driver_util::WriteToTemp(stdin, output_path);
}
- pid_t pid = fork();
-
- if (!pid) {
- // In child process.
-
- // Set the user to the one that initiated print job.
- SetUser(argv[2]);
+ // Change back to user to launch Chrome.
+ printer_driver_util::SetUser(argv[2]);
+ PLOG(ERROR) << print_ticket;
+ // Launch Chrome and pass the print job onto Cloud Print.
+ printer_driver_util::LaunchPrintDialog(output_path.value(), job_title,
+ current_user, print_ticket);
- // Launch Chrome and pass the print job onto Cloud Print.
- LaunchPrintDialog(output_path.value(), job_title, current_user);
-
- return 0;
- }
- // back in parent process.
- // wait for child, then terminate.
- waitpid(pid, NULL, 0);
return 0;
}
diff --git a/cloud_print/virtual_driver/posix/virtual_driver_posix_tests.cc b/cloud_print/virtual_driver/posix/virtual_driver_posix_tests.cc
new file mode 100644
index 0000000..34869af
--- /dev/null
+++ b/cloud_print/virtual_driver/posix/virtual_driver_posix_tests.cc
@@ -0,0 +1,75 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "cloud_print/virtual_driver/posix/printer_driver_util_posix.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace printer_driver_util {
+
+void test_helper(const char* input, std::string expected_output) {
+ std::string test;
+ GetOptions(input, &test);
+ EXPECT_EQ(expected_output, test);
+}
+
+TEST(PrintTicketTest, HandlesEmpty) {
+ test_helper("", "{}");
+}
+
+TEST(PrintTicketTest, HandlesNull) {
+ test_helper(NULL, "{}");
+}
+
+TEST(PrintTicketTest, HandlesOneOption) {
+ test_helper("Resolution=500", "{\"Resolution\":\"500\"}");
+}
+
+TEST(PrintTicketTest, HandlesMutipleOptions) {
+ test_helper("Resolution=500 DPI=1100",
+ "{\"DPI\":\"1100\",\"Resolution\":\"500\"}");
+}
+
+TEST(PrintTicketTest, HandlesErrorInOptions) {
+ test_helper("Resolution=500 Foo DPI=1100",
+ "{\"DPI\":\"1100\",\"Resolution\":\"500\"}");
+}
+
+TEST(PrintTicketTest, HandlesMutipleSpaces) {
+ test_helper("Resolution=500 DPI=1100",
+ "{\"DPI\":\"1100\",\"Resolution\":\"500\"}");
+}
+
+TEST(PrintTicketTest, HandlesEscapedSpace) {
+ test_helper("Job\\ Owner=First\\ Last",
+ "{\"Job Owner\":\"First Last\"}");
+}
+
+TEST(PrintTicketTest, HandlesMultipleEscapedWords) {
+ test_helper("Job\\ Owner\\ Name=First\\ Last",
+ "{\"Job Owner Name\":\"First Last\"}");
+}
+
+TEST(PrintTicketTest, HandlesMultipleEscapedSpaces) {
+ test_helper("Job\\ Owner\\ \\ Name=First\\ Last",
+ "{\"Job Owner Name\":\"First Last\"}");
+}
+
+TEST(PrintTicketTest, HandlesKeyEndsInEscapedSpace) {
+ test_helper("Job\\ Owner\\ =First\\ Last",
+ "{\"Job Owner \":\"First Last\"}");
+}
+
+TEST(PrintTicketTest, HandlesSlashAtEnd) {
+ test_helper("Job\\ Owner=First\\ Last\\",
+ "{\"Job Owner\":\"First Last\\\\\"}");
+}
+
+
+} // namespace printer_driver_util
+
+int main(int argc, char **argv) {
+ ::testing::InitGoogleTest(&argc, argv);
+ return RUN_ALL_TESTS();
+}
+
diff --git a/cloud_print/virtual_driver/virtual_driver_switches.cc b/cloud_print/virtual_driver/virtual_driver_switches.cc
index 72114bf..e8bd347 100644
--- a/cloud_print/virtual_driver/virtual_driver_switches.cc
+++ b/cloud_print/virtual_driver/virtual_driver_switches.cc
@@ -9,5 +9,6 @@ const char kCloudPrintDeleteFile[] = "cloud-print-delete-file";
const char kCloudPrintFile[] = "cloud-print-file";
const char kCloudPrintJobTitle[] = "cloud-print-job-title";
const char kCloudPrintFileType[] = "cloud-print-file-type";
+const char kCloudPrintPrintTicket[] = "cloud-print-print-ticket";
} // namespace switches
diff --git a/cloud_print/virtual_driver/virtual_driver_switches.h b/cloud_print/virtual_driver/virtual_driver_switches.h
index f30d9d1..54db54c 100644
--- a/cloud_print/virtual_driver/virtual_driver_switches.h
+++ b/cloud_print/virtual_driver/virtual_driver_switches.h
@@ -28,6 +28,11 @@ extern const char kCloudPrintJobTitle[];
// file referenced by cloud-print-file.
// Defaults to "application/pdf" if unspecified.
extern const char kCloudPrintFileType[];
+
+// Used with kCloudPrintFile to specify a JSON print ticket for the resulting
+// print job.
+// Defaults to null if unspecified.
+extern const char kCloudPrintPrintTicket[];
} // namespace switches
#endif // CLOUD_PRINT_VIRTUAL_DRIVER_VIRTUAL_DRIVER_SWITCHES_H_