@@ -207,7 +207,7 @@ async fn run() -> Result<(), GwsError> {
207207 }
208208
209209 // Walk the subcommand tree to find the target method
210- let ( method, matched_args) = resolve_method_from_matches ( & doc, & matches) ?;
210+ let ( method, matched_args, method_path ) = resolve_method_from_matches ( & doc, & matches) ?;
211211
212212 let params_json = matched_args. get_one :: < String > ( "params" ) . map ( |s| s. as_str ( ) ) ;
213213 let body_json = matched_args
@@ -228,6 +228,22 @@ async fn run() -> Result<(), GwsError> {
228228 . map ( |s| s. as_str ( ) ) ;
229229
230230 let dry_run = matched_args. get_flag ( "dry-run" ) ;
231+ let draft_only = matches. get_flag ( "draft-only" ) ;
232+ if draft_only && !dry_run && api_name == "gmail" {
233+ let is_send_method = if let Some ( ref id) = method. id {
234+ id == "gmail.users.messages.send" || id == "gmail.users.drafts.send"
235+ } else {
236+ // Fallback to path if ID is missing (suggested by previous review for robustness)
237+ method_path. len ( ) == 3
238+ && method_path[ 0 ] == "users"
239+ && ( method_path[ 1 ] == "messages" || method_path[ 1 ] == "drafts" )
240+ && method_path[ 2 ] == "send"
241+ } ;
242+
243+ if is_send_method {
244+ return Err ( GwsError :: Validation ( "Gmail draft-only mode is active. Sending mail is blocked (preparing a draft is still allowed)." . to_string ( ) ) ) ;
245+ }
246+ }
231247
232248 // Build pagination config from flags
233249 let pagination = parse_pagination_config ( matched_args) ;
@@ -361,13 +377,13 @@ fn parse_sanitize_config(
361377fn resolve_method_from_matches < ' a > (
362378 doc : & ' a discovery:: RestDescription ,
363379 matches : & ' a clap:: ArgMatches ,
364- ) -> Result < ( & ' a discovery:: RestMethod , & ' a clap:: ArgMatches ) , GwsError > {
380+ ) -> Result < ( & ' a discovery:: RestMethod , & ' a clap:: ArgMatches , Vec < String > ) , GwsError > {
365381 // Walk the subcommand chain
366- let mut path: Vec < & str > = Vec :: new ( ) ;
382+ let mut path: Vec < String > = Vec :: new ( ) ;
367383 let mut current_matches = matches;
368384
369385 while let Some ( ( sub_name, sub_matches) ) = current_matches. subcommand ( ) {
370- path. push ( sub_name) ;
386+ path. push ( sub_name. to_string ( ) ) ;
371387 current_matches = sub_matches;
372388 }
373389
@@ -379,7 +395,7 @@ fn resolve_method_from_matches<'a>(
379395
380396 // path looks like ["files", "list"] or ["files", "permissions", "list"]
381397 // Walk the Discovery Document resources to find the method
382- let resource_name = path[ 0 ] ;
398+ let resource_name = & path[ 0 ] ;
383399 let resource = doc
384400 . resources
385401 . get ( resource_name)
@@ -388,7 +404,7 @@ fn resolve_method_from_matches<'a>(
388404 let mut current_resource = resource;
389405
390406 // Navigate sub-resources (everything except the last element, which is the method)
391- for & name in & path[ 1 ..path. len ( ) - 1 ] {
407+ for name in & path[ 1 ..path. len ( ) - 1 ] {
392408 // Check if this is a sub-resource
393409 if let Some ( sub) = current_resource. resources . get ( name) {
394410 current_resource = sub;
@@ -400,11 +416,11 @@ fn resolve_method_from_matches<'a>(
400416 }
401417
402418 // The last element is the method name
403- let method_name = path[ path. len ( ) - 1 ] ;
419+ let method_name = & path[ path. len ( ) - 1 ] ;
404420
405421 // Check if this is a method on the current resource
406422 if let Some ( method) = current_resource. methods . get ( method_name) {
407- return Ok ( ( method, current_matches) ) ;
423+ return Ok ( ( method, current_matches, path ) ) ;
408424 }
409425
410426 // Maybe it's a resource that has methods — need one more subcommand
@@ -488,6 +504,9 @@ fn print_usage() {
488504 println ! ( ) ;
489505 println ! ( "DISCLAIMER:" ) ;
490506 println ! ( " This is not an officially supported Google product." ) ;
507+ println ! ( ) ;
508+ println ! ( "DISCLAIMER:" ) ;
509+ println ! ( " This is not an officially supported Google product." ) ;
491510}
492511
493512fn is_help_flag ( arg : & str ) -> bool {
@@ -622,8 +641,9 @@ mod tests {
622641 . subcommand ( clap:: Command :: new ( "files" ) . subcommand ( clap:: Command :: new ( "list" ) ) ) ;
623642
624643 let matches = cmd. get_matches_from ( vec ! [ "gws" , "files" , "list" ] ) ;
625- let ( method, _) = resolve_method_from_matches ( & doc, & matches) . unwrap ( ) ;
644+ let ( method, _, method_path ) = resolve_method_from_matches ( & doc, & matches) . unwrap ( ) ;
626645 assert_eq ! ( method. id. as_deref( ) , Some ( "drive.files.list" ) ) ;
646+ assert_eq ! ( method_path, vec![ "files" , "list" ] ) ;
627647 }
628648
629649 #[ test]
@@ -655,8 +675,9 @@ mod tests {
655675 ) ) ;
656676
657677 let matches = cmd. get_matches_from ( vec ! [ "gws" , "files" , "permissions" , "get" ] ) ;
658- let ( method, _) = resolve_method_from_matches ( & doc, & matches) . unwrap ( ) ;
678+ let ( method, _, method_path ) = resolve_method_from_matches ( & doc, & matches) . unwrap ( ) ;
659679 assert_eq ! ( method. id. as_deref( ) , Some ( "drive.files.permissions.get" ) ) ;
680+ assert_eq ! ( method_path, vec![ "files" , "permissions" , "get" ] ) ;
660681 }
661682
662683 #[ test]
0 commit comments