All of lore.kernel.org
 help / color / mirror / Atom feed
From: rmccabe@sourceware.org <rmccabe@sourceware.org>
To: cluster-devel.redhat.com
Subject: [Cluster-devel] conga/luci cluster/form-chooser cluster/form-m ...
Date: 23 Feb 2007 22:07:47 -0000	[thread overview]
Message-ID: <20070223220747.24209.qmail@sourceware.org> (raw)

CVSROOT:	/cvs/cluster
Module name:	conga
Changes by:	rmccabe at sourceware.org	2007-02-23 22:07:45

Modified files:
	luci/cluster   : form-chooser form-macros 
	luci/homebase  : luci_homebase.css 
	luci/site/luci/Extensions: cluster_adapters.py 
	                           conga_constants.py ricci_bridge.py 
Added files:
	luci/cluster   : validate_sys_svc.js 
	luci/plone-custom: conga_ajax.js svc_reload.png 
	                   svc_reload_active.png svc_reload_disabled.png 
	                   svc_start.png svc_start_active.png 
	                   svc_start_disabled.png svc_stop.png 
	                   svc_stop_active.png svc_stop_disabled.png 
	luci/site/luci/Extensions: system_adapters.py 

Log message:
	- System service management interface (chkconfig / service start/stop/restart)

Patches:
http://sourceware.org/cgi-bin/cvsweb.cgi/conga/luci/cluster/validate_sys_svc.js.diff?cvsroot=cluster&r1=NONE&r2=1.1
http://sourceware.org/cgi-bin/cvsweb.cgi/conga/luci/cluster/form-chooser.diff?cvsroot=cluster&r1=1.16&r2=1.17
http://sourceware.org/cgi-bin/cvsweb.cgi/conga/luci/cluster/form-macros.diff?cvsroot=cluster&r1=1.192&r2=1.193
http://sourceware.org/cgi-bin/cvsweb.cgi/conga/luci/homebase/luci_homebase.css.diff?cvsroot=cluster&r1=1.39&r2=1.40
http://sourceware.org/cgi-bin/cvsweb.cgi/conga/luci/plone-custom/conga_ajax.js.diff?cvsroot=cluster&r1=NONE&r2=1.1
http://sourceware.org/cgi-bin/cvsweb.cgi/conga/luci/plone-custom/svc_reload.png.diff?cvsroot=cluster&r1=NONE&r2=1.1
http://sourceware.org/cgi-bin/cvsweb.cgi/conga/luci/plone-custom/svc_reload_active.png.diff?cvsroot=cluster&r1=NONE&r2=1.1
http://sourceware.org/cgi-bin/cvsweb.cgi/conga/luci/plone-custom/svc_reload_disabled.png.diff?cvsroot=cluster&r1=NONE&r2=1.1
http://sourceware.org/cgi-bin/cvsweb.cgi/conga/luci/plone-custom/svc_start.png.diff?cvsroot=cluster&r1=NONE&r2=1.1
http://sourceware.org/cgi-bin/cvsweb.cgi/conga/luci/plone-custom/svc_start_active.png.diff?cvsroot=cluster&r1=NONE&r2=1.1
http://sourceware.org/cgi-bin/cvsweb.cgi/conga/luci/plone-custom/svc_start_disabled.png.diff?cvsroot=cluster&r1=NONE&r2=1.1
http://sourceware.org/cgi-bin/cvsweb.cgi/conga/luci/plone-custom/svc_stop.png.diff?cvsroot=cluster&r1=NONE&r2=1.1
http://sourceware.org/cgi-bin/cvsweb.cgi/conga/luci/plone-custom/svc_stop_active.png.diff?cvsroot=cluster&r1=NONE&r2=1.1
http://sourceware.org/cgi-bin/cvsweb.cgi/conga/luci/plone-custom/svc_stop_disabled.png.diff?cvsroot=cluster&r1=NONE&r2=1.1
http://sourceware.org/cgi-bin/cvsweb.cgi/conga/luci/site/luci/Extensions/system_adapters.py.diff?cvsroot=cluster&r1=NONE&r2=1.1
http://sourceware.org/cgi-bin/cvsweb.cgi/conga/luci/site/luci/Extensions/cluster_adapters.py.diff?cvsroot=cluster&r1=1.243&r2=1.244
http://sourceware.org/cgi-bin/cvsweb.cgi/conga/luci/site/luci/Extensions/conga_constants.py.diff?cvsroot=cluster&r1=1.36&r2=1.37
http://sourceware.org/cgi-bin/cvsweb.cgi/conga/luci/site/luci/Extensions/ricci_bridge.py.diff?cvsroot=cluster&r1=1.58&r2=1.59

/cvs/cluster/conga/luci/cluster/validate_sys_svc.js,v  -->  standard output
revision 1.1
--- conga/luci/cluster/validate_sys_svc.js
+++ -	2007-02-23 22:07:45.984856000 +0000
@@ -0,0 +1,22 @@
+function svc_callback() {
+	if (xmlHttp_object.readyState == 4) {
+		if (xmlHttp_object.status == 200) {
+			var response = xmlHttp_object.responseXML;
+			if (response) {
+				req_status = response.getAttribute('success');
+				req_op = response.getAttribute('operation');
+				req_svc = response.getAttribute('service');
+				req_msg = response.getAttribute('message');
+				//alert(req_msg + ' / ' + req_status + ' / ' + req_op + ' / ' + req_svc);
+			} else {
+				alert(xmlHttp_object.responseText);
+			}
+		} else {
+			//alert('Error retrieving data from server: ' + xmlHttp_object.status);
+		}
+	}
+}
+
+function update_sys_svc(url) {
+	initiate_async_get(url, svc_callback);
+}
--- conga/luci/cluster/form-chooser	2007/02/01 20:27:33	1.16
+++ conga/luci/cluster/form-chooser	2007/02/23 22:07:45	1.17
@@ -149,11 +149,15 @@
     <span tal:omit-tag="" tal:condition="python: ptype == '55'">
      <div metal:use-macro="here/form-macros/macros/fencedevprocess-form"/>
     </span>
-
     <span tal:omit-tag="" tal:condition="python: ptype == '80'">
      <div metal:use-macro="here/form-macros/macros/conf_editor-form"/>
     </span>
-
+    <span tal:omit-tag="" tal:condition="python: ptype == '90'">
+     <div metal:use-macro="here/form-macros/macros/system-svc-form"/>
+    </span>
+    <span tal:omit-tag="" tal:condition="python: ptype == '91'">
+     <div metal:use-macro="here/form-macros/macros/system-svc-update-form"/>
+    </span>
    </span>
   </metal:choose-form>
   </body>
--- conga/luci/cluster/form-macros	2007/02/20 23:06:59	1.192
+++ conga/luci/cluster/form-macros	2007/02/23 22:07:45	1.193
@@ -5022,10 +5022,110 @@
 	</div>
 </div>
 
+
 <div metal:define-macro="fencedevprocess-form">
 	<h2>Fence Device Process Form</h2>
 </div>
 
+<div metal:define-macro="system-svc-form">
+	<script type="text/javascript"
+		src="conga_ajax.js">
+	</script>
+	<script type="text/javascript"
+		src="/luci/cluster/validate_sys_svc.js">
+	</script>
+	<h2>Configure System Services</h2>
+
+	<form name="svcform" method="post" action="">
+
+	<input type="hidden" name="pagetype"
+		tal:attributes="value request/pagetype | nothing" />
+
+	<input type="hidden" name="systemname"
+		tal:attributes="value request/systemname | nothing" />
+
+	<table class="systemsTable"
+		tal:define="svcinfo python:'systemname' in request and here.get_sys_svc_list(request, request['systemname']) or []">
+		<tr class="systemsTable">
+			<th class="systemsTable">Name</th>
+			<th class="systemsTable">State</th>
+			<th class="systemsTable">Enabled at boot</th>
+			<th></th>
+		</tr>
+
+		<tr tal:repeat="s svcinfo">
+			<td class="systemsTable">
+				<span tal:content="s/name |string:[unknown]"
+					tal:attributes="title s/desc | nothing" />
+			</td>
+
+			<td class="systemsTable">
+				<span
+					tal:content="s/state |string:[unknown]"
+					tal:attributes="id python: '__STATUS__:' + s['name']" />
+			</td>
+
+			<td class="systemsTable">
+				<input type="checkbox"
+					tal:attributes="
+						name s/name;
+						id s/name;
+						checked python: s['enabled'] and 'checked' or ''"
+				/>
+			</td>
+
+			<td class="systemsTable"
+				tal:define="
+					restart_disabled python:not s['running'] and 'disabled' or '';
+					start_disabled python:s['running'] and 'disabled' or '';
+					stop_disabled python:not s['running'] and 'disabled' or ''">
+
+				<input type="button"
+					title="start this service"
+					class="svc_control svc_control_start"
+					onfocus="if (this.blur) this.blur()"
+					tal:attributes="
+						onclick python: 'update_sys_svc(\'' + s['starturl'] + '\')';
+						id python: '__START__' + s['name'];
+						name python: '__START__' + s['name'];
+						disabled start_disabled" />
+
+				<input type="button"
+					title="restart this service"
+					class="svc_control svc_control_restart"
+					onfocus="if (this.blur) this.blur()"
+					tal:attributes="
+						onclick python: 'update_sys_svc(\'' + s['restarturl'] + '\')';
+						id python: '__RESTART__' + s['name'];
+						name python: '__RESTART__' + s['name'];
+						disabled restart_disabled" />
+
+				<input type="button"
+					title="stop this service"
+					class="svc_control svc_control_stop"
+					onfocus="if (this.blur) this.blur()"
+					tal:attributes="
+						onclick python: 'update_sys_svc(\'' + s['stopurl'] + '\')';
+						id python: '__STOP__' + s['name'];
+						name python: '__STOP__' + s['name'];
+						disabled stop_disabled" />
+			</td>
+		</tr>
+		<tr class="systemsTable">
+			<td>
+				<div class="hbSubmit">
+					<input type="submit" value="Update" />
+				</div>
+			</td>
+		</tr>
+	</table>
+	</form>
+</div>
+
+<div metal:define-macro="system-svc-update-form">
+	<tal:block tal:define="ret python: here.validate_manage_svc(request)" />
+</div>
+
 <div metal:define-macro="conf_editor-form">
 	<h2>Edit cluster.conf</h2>
 	<form method="post"
--- conga/luci/homebase/luci_homebase.css	2007/02/08 05:05:22	1.39
+++ conga/luci/homebase/luci_homebase.css	2007/02/23 22:07:45	1.40
@@ -8,6 +8,60 @@
 	font-size: 12px;
 }
 
+input[type=image] {
+	border: 0;
+	background: transparent;
+	padding-left: +.3333em;
+	padding-right: +.3333em;
+}
+
+input[type=image]:disabled {
+	cursor: url('cursor-disabled.png'), default;
+}
+
+input.svc_control {
+	color: transparent ! important;
+	border: none ! important;
+	outline: hidden ! important;
+	background-color: transparent ! important;
+	background-repeat: no-repeat ! important;
+	cursor: pointer;
+}
+
+.svc_control_start {
+	background-image: url(svc_start.png);
+}
+
+input.svc_control_start:hover, input.svc_control_start:active {
+	background-image: url(svc_start_active.png) ! important;
+}
+input.svc_control_start:disabled {
+	background-image: url(svc_start_disabled.png) ! important;
+	cursor: url('cursor-disabled.png'), default;
+}
+
+input.svc_control_restart {
+	background-image: url(svc_reload.png);
+}
+input.svc_control_restart:hover, input.svc_control_restart:active {
+	background-image: url(svc_reload_active.png) ! important;
+}
+input.svc_control_restart:disabled {
+	background-image: url(svc_reload_disabled.png) ! important;
+	cursor: url('cursor-disabled.png'), default;
+}
+
+input.svc_control_stop {
+	background-image: url(svc_stop.png);
+}
+input.svc_control_stop:hover, input.svc_control_stop:active {
+	background-image: url(svc_stop_active.png) ! important;
+}
+input.svc_control_stop:disabled {
+	background-image: url(svc_stop_disabled.png) ! important;
+	cursor: url('cursor-disabled.png'), default;
+}
+
 input[type=checkbox], input[type=radio] {
 	float: left ! important;
 	vertical-align: middle;
/cvs/cluster/conga/luci/plone-custom/conga_ajax.js,v  -->  standard output
revision 1.1
--- conga/luci/plone-custom/conga_ajax.js
+++ -	2007-02-23 22:07:46.355394000 +0000
@@ -0,0 +1,29 @@
+var xmlHttp_object = false;
+
+function initiate_async_get(url, callback_function) {
+	xmlHttp_object = false;
+
+	if (!xmlHttp_object && typeof XMLHttpRequest != 'undefined') {
+		try {
+			xmlHttp_object = new XMLHttpRequest();
+		} catch (e0) {
+			try {
+				xmlHttp_object = new ActiveXObject("Msxml2.XMLHTTP");
+			} catch (e) {
+				try {
+					xmlHttp_object = new ActiveXObject("Microsoft.XMLHTTP");
+				} catch (e2) {
+					xmlHttp_object = false;
+				}
+			}
+		}
+	}
+
+	if (xmlHttp_object) {
+		xmlHttp_object.open("GET", url, true);
+		xmlHttp_object.onreadystatechange = callback_function;
+		xmlHttp_object.send(null);
+	} else {
+		alert("Unable to communicate with the luci server.");
+	}
+}
/cvs/cluster/conga/luci/plone-custom/svc_reload.png,v  -->  standard output
revision 1.1
Binary files /cvs/cluster/conga/luci/plone-custom/svc_reload.png and - differ
/cvs/cluster/conga/luci/plone-custom/svc_reload_active.png,v  -->  standard output
revision 1.1
Binary files /cvs/cluster/conga/luci/plone-custom/svc_reload_active.png and - differ
/cvs/cluster/conga/luci/plone-custom/svc_reload_disabled.png,v  -->  standard output
revision 1.1
Binary files /cvs/cluster/conga/luci/plone-custom/svc_reload_disabled.png and - differ
/cvs/cluster/conga/luci/plone-custom/svc_start.png,v  -->  standard output
revision 1.1
Binary files /cvs/cluster/conga/luci/plone-custom/svc_start.png and - differ
/cvs/cluster/conga/luci/plone-custom/svc_start_active.png,v  -->  standard output
revision 1.1
Binary files /cvs/cluster/conga/luci/plone-custom/svc_start_active.png and - differ
/cvs/cluster/conga/luci/plone-custom/svc_start_disabled.png,v  -->  standard output
revision 1.1
Binary files /cvs/cluster/conga/luci/plone-custom/svc_start_disabled.png and - differ
/cvs/cluster/conga/luci/plone-custom/svc_stop.png,v  -->  standard output
revision 1.1
Binary files /cvs/cluster/conga/luci/plone-custom/svc_stop.png and - differ
/cvs/cluster/conga/luci/plone-custom/svc_stop_active.png,v  -->  standard output
revision 1.1
Binary files /cvs/cluster/conga/luci/plone-custom/svc_stop_active.png and - differ
/cvs/cluster/conga/luci/plone-custom/svc_stop_disabled.png,v  -->  standard output
revision 1.1
Binary files /cvs/cluster/conga/luci/plone-custom/svc_stop_disabled.png and - differ
/cvs/cluster/conga/luci/site/luci/Extensions/system_adapters.py,v  -->  standard output
revision 1.1
--- conga/luci/site/luci/Extensions/system_adapters.py
+++ -	2007-02-23 22:07:47.286199000 +0000
@@ -0,0 +1,134 @@
+from ricci_communicator import RicciCommunicator
+from ricci_bridge import list_services, updateServices, svc_manage
+from LuciSyslog import LuciSyslog
+
+try: 
+	luci_log = LuciSyslog()
+except:
+	pass
+
+def get_sys_svc_list(self, request, hostname):
+	try:
+		rc = RicciCommunicator(hostname)
+		if not rc:
+			raise Exception, 'None'
+	except Exception, e:
+		luci_log.debug_verbose('GSSL0: %s: %s' % (hostname, str(e)))
+		return []
+
+	service_list = list_services(rc)
+	if not service_list:
+		return []
+
+	svc_ret = list()
+	for i in service_list:
+		s = {}
+		try:
+			name = str(i.getAttribute('name'))
+		except:
+			name = None
+		s['name'] = name
+
+		try:
+			desc = i.getAttribute('description')
+		except:
+			desc = None
+		s['desc'] = desc
+
+		try:
+			enabled = i.getAttribute('enabled').lower()
+			if enabled == 'true':
+				s['enabled'] = True
+			else:
+				raise Exception, 'not enabled'
+		except:
+			s['enabled'] = False
+
+		try:
+			running = i.getAttribute('running').lower()
+			if running == 'true':
+				s['running'] = True
+				s['state'] = 'Running'
+			else:
+				raise Exception, 'not running'
+		except Exception, e:
+			s['running'] = False
+			s['state'] = 'Stopped'
+
+		s['starturl'] = '%s?pagetype=91&svcname=%s&systemname=%s&operation=start' % (request['URL'], s['name'], hostname)
+		s['stopurl'] = '%s?pagetype=91&svcname=%s&systemname=%s&operation=stop' % (request['URL'], s['name'], hostname)
+		s['restarturl'] = '%s?pagetype=91&svcname=%s&systemname=%s&operation=restart' % (request['URL'], s['name'], hostname)
+		svc_ret.append(s)
+
+	return svc_ret
+
+def validate_svc_update(self, request):
+	try:
+		form = request.form
+		hostname = form['systemname'].strip()
+		if not hostname:
+			raise Exception, 'blank'
+	except Exception, e:
+		return (False, {'errors': [ 'No system name was given.' ]})
+
+	try:
+		rc = RicciCommunicator(hostname)
+		if not rc:
+			raise Exception, 'unknown error'
+	except Exception, e:
+		luci_log.debug_verbose('VSU0: %s: %s' % (hostname, str(e)))
+		return (False, {'errors': [ 'Unable to connect to the ricci agent on %s: %s' % (hostname, str(e)) ]})
+
+	sys_svc_list = list()
+	sys_svc_hash = dict()
+
+	try:
+		for i in list_services(rc):
+			svc_name = str(i.getAttribute('name'))
+			sys_svc_hash[svc_name] = i
+			sys_svc_list.append(svc_name)
+	except Exception, e:
+		luci_log.debug_verbose('VSU1: %s: %s' % (hostname, str(e)))
+		return (False, {'errors': [ 'Unable to retrieve the list of services from %s' % hostname ]})
+
+	try:
+		del form['pagetype']
+		del form['systemname']
+	except:
+		pass
+
+	disable_list = filter(lambda x: not form.has_key(x) and sys_svc_hash[x].getAttribute('enabled').lower() == 'true', sys_svc_list)
+	enable_list = filter(lambda x: form.has_key(x) and sys_svc_hash[x].getAttribute('enabled').lower() != 'true', sys_svc_list)
+
+	updateServices(rc, enable_list, disable_list)
+	request.RESPONSE.redirect(request['URL'] + '?pagetype=90&systemname=' + hostname)
+
+def validate_manage_svc(self, request):
+	try:
+		hostname = request['systemname'].strip()
+	except:
+		return None
+
+	servicename = None
+	op = None
+	try:
+		servicename = request['svcname'].strip()
+		op = request['operation'].strip()
+	except:
+		pass
+
+	try:
+		rc = RicciCommunicator(hostname)
+		if not rc:
+			raise Exception, 'none'
+	except Exception, e:
+		return None
+
+	ret = None
+	try:
+		ret = svc_manage(rc, hostname, servicename, op)
+		luci_log.debug_verbose('VMC0: returning %s' % str(ret.toxml()))
+	except:
+		pass
+
+	return ret
--- conga/luci/site/luci/Extensions/cluster_adapters.py	2007/02/22 20:52:51	1.243
+++ conga/luci/site/luci/Extensions/cluster_adapters.py	2007/02/23 22:07:45	1.244
@@ -41,6 +41,7 @@
 from GeneralError import GeneralError
 from homebase_adapters import manageCluster, createClusterSystems, havePermCreateCluster, setNodeFlag, delNodeFlag, userAuthenticated, getStorageNode, getClusterNode, delCluster, parseHostForm
 from LuciSyslog import LuciSyslog
+from system_adapters import validate_svc_update
 
 #Policy for showing the cluster chooser menu:
 #1) If there are no clusters in the ManagedClusterSystems
@@ -2453,7 +2454,8 @@
 	54: validateFenceEdit,
 	55: validateDaemonProperties,
 	57: deleteFenceDevice,
-	58: validateNodeFenceConfig
+	58: validateNodeFenceConfig,
+	90: validate_svc_update
 }
 
 def validatePost(self, request):
--- conga/luci/site/luci/Extensions/conga_constants.py	2007/02/01 20:49:08	1.36
+++ conga/luci/site/luci/Extensions/conga_constants.py	2007/02/23 22:07:45	1.37
@@ -48,6 +48,8 @@
 FENCEDEV_NODE_CONFIG = '58'
 
 CONF_EDITOR = '80'
+SYS_SERVICE_MANAGE = '90'
+SYS_SERVICE_UPDATE = '91'
 
 #Cluster tasks
 CLUSTER_STOP = '1000'
--- conga/luci/site/luci/Extensions/ricci_bridge.py	2007/02/22 20:52:51	1.58
+++ conga/luci/site/luci/Extensions/ricci_bridge.py	2007/02/23 22:07:45	1.59
@@ -486,6 +486,70 @@
 	ricci_xml = rc.batch_run(batch_str)
 	return batchAttemptResult(ricci_xml)
 
+def svc_manage(rc, hostname, servicename, op):
+	svc_func = None
+
+	doc = minidom.Document()
+	elem = doc.createElement('result')
+
+	if not servicename:
+		elem.setAttribute('service', 'No service name was specified.')
+		elem.setAttribute('message', 'No service name was specified.')
+		elem.setAttribute('success', '0')
+
+	if not op:
+		elem.setAttribute('operation', 'No operation was specified.')
+		elem.setAttribute('message', 'No operation was specified.')
+		elem.setAttribute('success', '0')
+
+	if not servicename or not op:
+		doc.appendChild(elem)
+		return doc
+
+	elem.setAttribute('service', servicename)
+	elem.setAttribute('operation', op)
+	elem.setAttribute('hostname', hostname)
+
+	try:
+		op = op.strip().lower()
+		if op == 'restart' or op == 'start' or op == 'stop':
+			svc_func = op
+		else:
+			raise Exception, op
+	except Exception, e:
+		elem.setAttribute('success', '0');
+		elem.setAttribute('message', 'Unknown operation')
+		doc.appendChild(elem)
+		return doc
+
+	batch_str = '<module name="service"><request API_version="1.0"><function_call name="%s"><var mutable="false" name="services" type="list_xml"><service name="%s"/></var></function_call></request></module>' % (svc_func, servicename)
+		
+	ricci_xml = rc.batch_run(batch_str, async=False)
+	if not ricci_xml or not ricci_xml.firstChild:
+		luci_log.debug_verbose('SVCM0: None returned')
+		elem.setAttribute('success', '0')
+		elem.setAttribute('message', 'operation failed')
+		doc.appendChild(elem)
+		return doc
+
+	elem.setAttribute('success', '0')
+	elem.setAttribute('message', str(ricci_xml.toxml()))
+	doc.appendChild(elem)
+	return doc
+
+def list_services(rc):
+	batch_str = '<module name="service"><request API_version="1.0"><function_call name="list"><var mutable="false" name="description" type="boolean" value="true"/></function_call></request></module>'
+	ricci_xml = rc.batch_run(batch_str, async=False)
+	if not ricci_xml or not ricci_xml.firstChild:
+		luci_log.debug_verbose('LS0: None returned')
+		return None
+	try:
+		service_tags = ricci_xml.getElementsByTagName('service')
+		return service_tags
+	except Exception, e:
+		luci_log.debug_verbose('LS1: %s' % str(e))
+	return None
+
 def nodeIsVirtual(rc):
 	batch_str = '<module name="cluster"><request API_version="1.0"><function_call name="virt_guest"/></request></module>'
 



             reply	other threads:[~2007-02-23 22:07 UTC|newest]

Thread overview: 10+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2007-02-23 22:07 rmccabe [this message]
  -- strict thread matches above, loose matches on Subject: below --
2007-09-25 22:47 [Cluster-devel] conga/luci cluster/form-chooser cluster/form-m rmccabe
2007-03-12  4:25 rmccabe
2007-03-12  4:24 rmccabe
2007-03-12  4:22 rmccabe
2006-12-21 21:26 kupcevic
2006-12-07 17:54 rmccabe
2006-12-06 18:38 rmccabe
2006-11-10 19:44 rmccabe
2006-10-09 17:12 rmccabe

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20070223220747.24209.qmail@sourceware.org \
    --to=rmccabe@sourceware.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.